Android O WiFi 获取扫描结果流程

版权声明:本文为博主原创文章,未经博主允许不得转载。https://blog.csdn.net/huangweiqing80/article/details/82458874
1. wifi扫描结果简介

WiFi的扫描结果会在WiFi扫描后呈现在设置WiFi界面上的,每个扫描到的AP是以Preference组件的方式呈现的设置WiFi界面上,点击即可触发连接操作。

2. 流程分析
2.1前面提到mWifiTracker.startTracking();会去扫描,那么onWifiStateChanged(mWifiManager.getWifiState())就是在wifi状态改变的时候去获取扫描结果

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

    @Override
    public void onStart() {
        super.onStart();

        // On/off switch is hidden for Setup Wizard (returns null)
        mWifiEnabler = createWifiEnabler();

        mWifiTracker.startTracking();

        if (mIsRestricted) {
            restrictUi();
            return;
        }

        onWifiStateChanged(mWifiManager.getWifiState());
    }

2.2 下面来看一下onWifiStateChanged源码

    /** 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:
                conditionallyForceUpdateAPs();
                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;
        }
    }

2.3这里wifi已经打开了,所以wifiState对应的是WifiManager.WIFI_STATE_ENABLED,所以走的应该是conditionallyForceUpdateAPs();这句

    /**
     * Only update the AP list if there are not any APs currently shown.
     *
     * <p>Thus forceUpdate will only be called during cold start or when toggling between wifi on
     * and off. In other use cases, the previous APs will remain until the next update is received
     * from {@link WifiTracker}.
     */
    private void conditionallyForceUpdateAPs() {
        if (mAccessPointsPreferenceCategory.getPreferenceCount() > 0
                && mAccessPointsPreferenceCategory.getPreference(0) instanceof
                        AccessPointPreference) {
            // Make sure we don't update due to callbacks initiated by sticky broadcasts in
            // WifiTracker.
            Log.d(TAG, "Did not force update APs due to existing APs displayed");
            getView().removeCallbacks(mUpdateAccessPointsRunnable);
            return;
        }
        setProgressBarVisible(true);
        mWifiTracker.forceUpdate();
        if (WifiTracker.sVerboseLogging) {
            Log.i(TAG, "WifiSettings force update APs: " + mWifiTracker.getAccessPoints());
        }
        getView().removeCallbacks(mUpdateAccessPointsRunnable);
        updateAccessPointPreferences();
    }

这里关键的是
mWifiTracker.forceUpdate(); //获取扫描结果
updateAccessPointPreferences(); //更新扫描结果组件,即将扫描结果显示到WIFI Setting界面
下面分别来看一下这两行代码

2.3.1先来看一下mWifiTracker.forceUpdate();
frameworks/base/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java

 /** Synchronously update the list of access points with the latest information. */
    @MainThread
    public void forceUpdate() {
        synchronized (mLock) {
            mWorkHandler.removeMessages(WorkHandler.MSG_UPDATE_ACCESS_POINTS);
            mLastInfo = mWifiManager.getConnectionInfo();
            mLastNetworkInfo = mConnectivityManager.getNetworkInfo(mWifiManager.getCurrentNetwork());

            final List<ScanResult> newScanResults = mWifiManager.getScanResults();
            if (sVerboseLogging) {
                Log.i(TAG, "Fetched scan results: " + newScanResults);
            }

            List<WifiConfiguration> configs = mWifiManager.getConfiguredNetworks();
            mInternalAccessPoints.clear();
            updateAccessPointsLocked(newScanResults, configs);

            // Synchronously copy access points
            mMainHandler.removeMessages(MainHandler.MSG_ACCESS_POINT_CHANGED);
            mMainHandler.handleMessage(
                    Message.obtain(mMainHandler, MainHandler.MSG_ACCESS_POINT_CHANGED));
            if (sVerboseLogging) {
                Log.i(TAG, "force update - external access point list:\n" + mAccessPoints);
            }
        }
    }

这个方法调用了WifiManager的getScanResults 和 getConfiguredNetworks。这两个函数分别是获取扫描结果和网络配置。
updateAccessPointsLocked(newScanResults, configs);这句是将扫描结果和网络配置放到哪里呢?

 /**
     * Update the internal list of access points.
     *
     * <p>Do not called directly (except for forceUpdate), use {@link #updateAccessPoints()} which
     * respects {@link #mStaleScanResults}.
     */
    @GuardedBy("mLock")
    private void updateAccessPointsLocked(final List<ScanResult> newScanResults,
            List<WifiConfiguration> configs) {
        WifiConfiguration connectionConfig = null;
        if (mLastInfo != null) {
            connectionConfig = getWifiConfigurationForNetworkId(
                    mLastInfo.getNetworkId(), mWifiManager.getConfiguredNetworks());
        }

        // Swap the current access points into a cached list.
        List<AccessPoint> cachedAccessPoints = new ArrayList<>(mInternalAccessPoints);
        ArrayList<AccessPoint> accessPoints = new ArrayList<>();

        // Clear out the configs so we don't think something is saved when it isn't.
        for (AccessPoint accessPoint : cachedAccessPoints) {
            accessPoint.clearConfig();
        }

    /* Lookup table to more quickly update AccessPoints by only considering objects with the
     * correct SSID.  Maps SSID -> List of AccessPoints with the given SSID.  */
        Multimap<String, AccessPoint> apMap = new Multimap<String, AccessPoint>();

        final Collection<ScanResult> results = updateScanResultCache(newScanResults);

        if (configs != null) {
            for (WifiConfiguration config : configs) {
                if (config.selfAdded && config.numAssociation == 0) {
                    continue;
                }
                AccessPoint accessPoint = getCachedOrCreate(config, cachedAccessPoints);
                if (mLastInfo != null && mLastNetworkInfo != null) {
                    accessPoint.update(connectionConfig, mLastInfo, mLastNetworkInfo);
                }
                if (mIncludeSaved) {
                    // If saved network not present in scan result then set its Rssi to
                    // UNREACHABLE_RSSI
                    boolean apFound = false;
                    for (ScanResult result : results) {
                        if (result.SSID.equals(accessPoint.getSsidStr())) {
                            apFound = true;
                            break;
                        }
                    }
                    if (!apFound) {
                        accessPoint.setUnreachable();
                    }
                    accessPoints.add(accessPoint);
                    apMap.put(accessPoint.getSsidStr(), accessPoint);
                } else {
                    // If we aren't using saved networks, drop them into the cache so that
                    // we have access to their saved info.
                    cachedAccessPoints.add(accessPoint);
                }
            }
        }

        final List<NetworkKey> scoresToRequest = new ArrayList<>();
        if (results != null) {
            for (ScanResult result : results) {
                // Ignore hidden and ad-hoc networks.
                if (result.SSID == null || result.SSID.length() == 0 ||
                        result.capabilities.contains("[IBSS]")) {
                    continue;
                }

                NetworkKey key = NetworkKey.createFromScanResult(result);
                if (key != null && !mRequestedScores.contains(key)) {
                    scoresToRequest.add(key);
                }

                boolean found = false;
                for (AccessPoint accessPoint : apMap.getAll(result.SSID)) {
                    // We want to evict old scan results if are current results are not stale
                    if (accessPoint.update(result, !mStaleScanResults)) {
                        found = true;
                        break;
                    }
                }
                if (!found && mIncludeScans) {
                    AccessPoint accessPoint = getCachedOrCreate(result, cachedAccessPoints);
                    if (mLastInfo != null && mLastNetworkInfo != null) {
                        accessPoint.update(connectionConfig, mLastInfo, mLastNetworkInfo);
                    }

                    if (result.isPasspointNetwork()) {
                        // Retrieve a WifiConfiguration for a Passpoint provider that matches
                        // the given ScanResult.  This is used for showing that a given AP
                        // (ScanResult) is available via a Passpoint provider (provider friendly
                        // name).
                        try {
                            WifiConfiguration config = mWifiManager.getMatchingWifiConfig(result);
                            if (config != null) {
                                accessPoint.update(config);
                            }
                        } catch (UnsupportedOperationException e) {
                            // Passpoint not supported on the device.
                        }
                    }

                    accessPoints.add(accessPoint);
                    apMap.put(accessPoint.getSsidStr(), accessPoint);
                }
            }
        }

        requestScoresForNetworkKeys(scoresToRequest);
        for (AccessPoint ap : accessPoints) {
            ap.update(mScoreCache, mNetworkScoringUiEnabled, mMaxSpeedLabelScoreCacheAge);
        }

        // Pre-sort accessPoints to speed preference insertion
        Collections.sort(accessPoints);

        // Log accesspoints that were deleted
        if (DBG()) {
            Log.d(TAG, "------ Dumping SSIDs that were not seen on this scan ------");
            for (AccessPoint prevAccessPoint : mInternalAccessPoints) {
                if (prevAccessPoint.getSsid() == null)
                    continue;
                String prevSsid = prevAccessPoint.getSsidStr();
                boolean found = false;
                for (AccessPoint newAccessPoint : accessPoints) {
                    if (newAccessPoint.getSsidStr() != null && newAccessPoint.getSsidStr()
                            .equals(prevSsid)) {
                        found = true;
                        break;
                    }
                }
                if (!found)
                    Log.d(TAG, "Did not find " + prevSsid + " in this scan");
            }
            Log.d(TAG, "---- Done dumping SSIDs that were not seen on this scan ----");
        }

        mInternalAccessPoints.clear();
        mInternalAccessPoints.addAll(accessPoints);

        mMainHandler.sendEmptyMessage(MainHandler.MSG_ACCESS_POINT_CHANGED);
    }

代码有点多,但是我们只看重点的下面四行代码,简单来看就是分两大块WifiConfiguration 和 ScanResult进行accessPoints的添加,并将accessPoints添加到mInternalAccessPoints。更新完了发送一个MSG_ACCESS_POINT_CHANGED消息
AccessPoint accessPoint = getCachedOrCreate(config, cachedAccessPoints);
AccessPoint accessPoint = getCachedOrCreate(result, cachedAccessPoints);
mInternalAccessPoints.addAll(accessPoints);
mMainHandler.sendEmptyMessage(MainHandler.MSG_ACCESS_POINT_CHANGED);
这样我们便将扫描结果添加到mInternalAccessPoints中了,并且发送一个MSG_ACCESS_POINT_CHANGED消息,调用了copyAndNotifyListeners方法。(PS:如注释所述这个方法不建议直接调用,建议调用updateAccessPoints())



                case MSG_ACCESS_POINT_CHANGED:
                    // Only notify listeners of changes if we have fresh scan results, otherwise the
                    // UI will be updated with stale results. We want to copy the APs regardless,
                    // for instances where forceUpdate was invoked by the caller.
                    if (mStaleScanResults) {
                        copyAndNotifyListeners(false /*notifyListeners*/);
                    } else {
                        copyAndNotifyListeners(true /*notifyListeners*/);
                        mListener.onAccessPointsChanged();
                    }
                    break;

下面来看看copyAndNotifyListeners这个方法里面做了什么

   /**
     * Responsible for copying access points from {@link #mInternalAccessPoints} and notifying
     * accesspoint listeners.
     *
     * @param notifyListeners if true, accesspoint listeners are notified, otherwise notifications
     *                        dropped.
     */
    @MainThread
    private void copyAndNotifyListeners(boolean notifyListeners) {
        // Need to watch out for memory allocations on main thread.
        SparseArray<AccessPoint> oldAccessPoints = new SparseArray<>();
        SparseIntArray notificationMap = null;
        List<AccessPoint> updatedAccessPoints = new ArrayList<>();

        for (AccessPoint accessPoint : mAccessPoints) {
            oldAccessPoints.put(accessPoint.mId, accessPoint);
        }

        synchronized (mLock) {
            if (DBG()) {
                Log.d(TAG, "Starting to copy AP items on the MainHandler. Internal APs: "
                        + mInternalAccessPoints);
            }

            if (notifyListeners) {
                notificationMap = mAccessPointListenerAdapter.mPendingNotifications.clone();
            }

            mAccessPointListenerAdapter.mPendingNotifications.clear();

            for (AccessPoint internalAccessPoint : mInternalAccessPoints) {
                AccessPoint accessPoint = oldAccessPoints.get(internalAccessPoint.mId);
                if (accessPoint == null) {
                    accessPoint = new AccessPoint(mContext, internalAccessPoint);
                } else {
                    accessPoint.copyFrom(internalAccessPoint);
                }
                updatedAccessPoints.add(accessPoint);
            }
        }

        mAccessPoints.clear();
        mAccessPoints.addAll(updatedAccessPoints);

        if (notificationMap != null && notificationMap.size() > 0) {
            for (AccessPoint accessPoint : updatedAccessPoints) {
                int notificationType = notificationMap.get(accessPoint.mId);
                AccessPoint.AccessPointListener listener = accessPoint.mAccessPointListener;
                if (notificationType == 0 || listener == null) {
                    continue;
                }

                if ((notificationType & AccessPointListenerAdapter.AP_CHANGED) != 0) {
                    listener.onAccessPointChanged(accessPoint);
                }

                if ((notificationType & AccessPointListenerAdapter.LEVEL_CHANGED) != 0) {
                    listener.onLevelChanged(accessPoint);
                }
            }
        }
    }

这块代码暂只关注扫描结果,大致分为三步

1.将之前的扫描结果存到oldAccessPoints:oldAccessPoints.put(accessPoint.mId, accessPoint);
2.根据mInternalAccessPoints构造新的扫描结果集合updatedAccessPoints
internalAccessPoint : mInternalAccessPoints
AccessPoint accessPoint = oldAccessPoints.get(internalAccessPoint.mId);
updatedAccessPoints.add(accessPoint);
3.将新的扫描结果集合赋给mAccessPoints :mAccessPoints.addAll(updatedAccessPoints);

这就是对mAccessPoints这个集合进行增减操作啊

2.3.2下面我们在回到更新AccessPointsPreference组件的地方updateAccessPointPreferences()

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

    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 (WifiTracker.sVerboseLogging) {
            Log.i(TAG, "updateAccessPoints called for: " + accessPoints);
        }

        boolean hasAvailableAccessPoints = false;
        mAccessPointsPreferenceCategory.removePreference(mStatusMessagePreference);
        cacheRemoveAllPrefs(mAccessPointsPreferenceCategory);

        int index =
                configureConnectedAccessPointPreferenceCategory(accessPoints) ? 1 : 0;
        int numAccessPoints = accessPoints.size();
        for (; index < numAccessPoints; index++) {
            AccessPoint accessPoint = accessPoints.get(index);
            // Ignore access points that are out of range.
            if (accessPoint.isReachable()) {
                String key = AccessPointPreference.generatePreferenceKey(accessPoint);
                hasAvailableAccessPoints = true;
                LongPressAccessPointPreference pref =
                        (LongPressAccessPointPreference) getCachedPreference(key);
                if (pref != null) {
                    pref.setOrder(index);
                    continue;
                }
                LongPressAccessPointPreference preference =
                        createLongPressActionPointPreference(accessPoint);
                preference.setKey(key);
                preference.setOrder(index);
                if (mOpenSsid != null && mOpenSsid.equals(accessPoint.getSsidStr())
                        && accessPoint.getSecurity() != AccessPoint.SECURITY_NONE) {
                    if (!accessPoint.isSaved() || isDisabledByWrongPassword(accessPoint)) {
                        onPreferenceTreeClick(preference);
                        mOpenSsid = null;
                    }
                }
                mAccessPointsPreferenceCategory.addPreference(preference);
                accessPoint.setListener(WifiSettings.this);
                preference.refresh();
            }
        }
        removeCachedPrefs(mAccessPointsPreferenceCategory);
        mAddPreference.setOrder(index);
        mAccessPointsPreferenceCategory.addPreference(mAddPreference);
        setAdditionalSettingsSummaries();

        if (!hasAvailableAccessPoints) {
            setProgressBarVisible(true);
            Preference pref = new Preference(getPrefContext());
            pref.setSelectable(false);
            pref.setSummary(R.string.wifi_empty_list_wifi_on);
            pref.setOrder(index++);
            pref.setKey(PREF_KEY_EMPTY_WIFI_LIST);
            mAccessPointsPreferenceCategory.addPreference(pref);
        } else {
            // Continuing showing progress bar for an additional delay to overlap with animation
            getView().postDelayed(mHideProgressBarRunnable, 1700 /* delay millis */);
        }
    }

如上是WifiSettings里更新AP preference的方法,主要调用了WifiTracker的getAccessPoint方法。

SettingsLib

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

    /**
     * Gets the current list of access points. Should be called from main thread, otherwise
     * expect inconsistencies
     */
    @MainThread
    public List<AccessPoint> getAccessPoints() {
        return new ArrayList<>(mAccessPoints);
    }

返回的这个mAccessPoints不就是我们在2.3.1中的更新的AP列表吗

2.4 framework(getScanResults)

我们回到2.3.1开头讲到的两个重要方法,getScanResults获取扫描结果和getConfiguredNetworks获取网络配置
先简单看下getScanResults方法,getConfiguredNetworks方法类似这里就暂不分析

2.4.1 WifiManager

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

mService已经很熟悉了,对应的服务端是WifiServiceImpl

2.4.2 WifiServiceImpl

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();
        try {
            if (!mWifiPermissionsUtil.canAccessScanResults(callingPackage,
                      uid, Build.VERSION_CODES.M)) {
                return new ArrayList<ScanResult>();
            }
            if (mWifiScanner == null) {
                mWifiScanner = mWifiInjector.getWifiScanner();
            }
            return mWifiScanner.getSingleScanResults();
        } finally {
            Binder.restoreCallingIdentity(ident);
        }
    }

    /**
     * Obtain an instance of WifiScanner.
     * If it was not already created, then obtain an instance.  Note, this must be done lazily since
     * WifiScannerService is separate and created later.
     */
    public synchronized WifiScanner getWifiScanner() {
        if (mWifiScanner == null) {
            mWifiScanner = new WifiScanner(mContext,
                    IWifiScanner.Stub.asInterface(ServiceManager.getService(
                            Context.WIFI_SCANNING_SERVICE)),
                    mWifiStateMachineHandlerThread.getLooper());
        }
        return mWifiScanner;
    }

可以看到前面调用了mWifiScanner.getSingleScanResults();另外getWifiScanner这边WifiScanner之前也梳理过了,IWifiScanner参数对应的服务端是WifiScanningServiceImpl了
下面来看看mWifiScanner.getSingleScanResults()

2.4.3 WifiScanner

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

    /**
     * Retrieve the most recent scan results from a single scan request.
     * {@hide}
     */
    public List<ScanResult> getSingleScanResults() {
        validateChannel();
        Message reply = mAsyncChannel.sendMessageSynchronously(CMD_GET_SINGLE_SCAN_RESULTS, 0);
        if (reply.what == WifiScanner.CMD_OP_SUCCEEDED) {
            return Arrays.asList(((ParcelableScanResults) reply.obj).getResults());
        }
        OperationResult result = (OperationResult) reply.obj;
        Log.e(TAG, "Error retrieving SingleScan results reason: " + result.reason
                + " description: " + result.description);
        return new ArrayList<ScanResult>();
    }

这边之前都分析过了通过AsyncChannel的IPC调用到WifiScanningServiceImpl的ClientHandler来处理WifiScanner.CMD_GET_SINGLE_SCAN_RESULTS消息,搜索结果是存放在reply.obj里的。

AsyncTask原理参照:https://blog.csdn.net/u010961631/article/details/48179305

2.4.4 WifiScanningServiceImpl

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

    private class ClientHandler extends WifiHandler {

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

        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what) {
                case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION: {
                    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 = mFrameworkFacade.makeWifiAsyncChannel(TAG);
                    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 {
                enforceLocationHardwarePermission(msg.sendingUid);
            } 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;
            }
        if (msg.what == WifiScanner.CMD_GET_SINGLE_SCAN_RESULTS) {
            mSingleScanStateMachine.sendMessage(Message.obtain(msg));
            return;
        }

2.4.5 继续交给SingleScanStateMachine来处理。这边稍微把这边的状态机状态梳理一下,分析一下状态机的状态变化。先来看一下状态机初始化添加状态,和初始化初始状态为mDefaultState
frameworks/opt/net/wifi/service/java/com/android/server/wifi/scanner/WifiScanningServiceImpl.java

        WifiSingleScanStateMachine(Looper looper) {
            super("WifiSingleScanStateMachine", looper);

            setLogRecSize(128);
            setLogOnlyTransitions(false);

            // CHECKSTYLE:OFF IndentationCheck
            addState(mDefaultState);
                addState(mDriverStartedState, mDefaultState);
                    addState(mIdleState, mDriverStartedState);
                    addState(mScanningState, mDriverStartedState);
            // CHECKSTYLE:ON IndentationCheck

            setInitialState(mDefaultState);
        }

这里写图片描述

在startService里会进行状态机的启动

    public void startService() {
        mClientHandler = new ClientHandler(TAG, mLooper);
        mBackgroundScanStateMachine = new WifiBackgroundScanStateMachine(mLooper);
        mSingleScanStateMachine = new WifiSingleScanStateMachine(mLooper);
        mPnoScanStateMachine = new WifiPnoScanStateMachine(mLooper);

        mContext.registerReceiver(
                new BroadcastReceiver() {
                    @Override
                    public void onReceive(Context context, Intent intent) {
                        int state = intent.getIntExtra(
                                WifiManager.EXTRA_SCAN_AVAILABLE, WifiManager.WIFI_STATE_DISABLED);
                        if (DBG) localLog("SCAN_AVAILABLE : " + state);
                        if (state == WifiManager.WIFI_STATE_ENABLED) {
                            mBackgroundScanStateMachine.sendMessage(CMD_DRIVER_LOADED);
                            mSingleScanStateMachine.sendMessage(CMD_DRIVER_LOADED);
                            mPnoScanStateMachine.sendMessage(CMD_DRIVER_LOADED);
                        } else if (state == WifiManager.WIFI_STATE_DISABLED) {
                            mBackgroundScanStateMachine.sendMessage(CMD_DRIVER_UNLOADED);
                            mSingleScanStateMachine.sendMessage(CMD_DRIVER_UNLOADED);
                            mPnoScanStateMachine.sendMessage(CMD_DRIVER_UNLOADED);
                        }
                    }
                }, new IntentFilter(WifiManager.WIFI_SCAN_AVAILABLE));

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

从startService中可以看到,如果WiFi已经打开,startService里面会调用mSingleScanStateMachine.sendMessage(CMD_DRIVER_LOADED);mSingleScanStateMachine里面的DefaultState 这边会监听到CMD_DRIVER_LOADED消息,然后我们切换到IdleState。

        class DefaultState extends State {
            @Override
            public void enter() {
                mActiveScans.clear();
                mPendingScans.clear();
            }
            @Override
            public boolean processMessage(Message msg) {
                switch (msg.what) {
                    case CMD_DRIVER_LOADED:
                        transitionTo(mIdleState);
                        return HANDLED;
        class IdleState extends State {
            @Override
            public void enter() {
                tryToStartNewScan();
            }

            @Override
            public boolean processMessage(Message msg) {
                return NOT_HANDLED;
            }
        }

切换到IdleState,会调用enter(),继而调用tryToStartNewScan,但是此时我们走的是else。所以此时并不会迁移到ScanningState。

在处理扫描阶段发出的CMD_START_SINGLE_SCAN继而调用tryToStartNewScan的时候才会迁移到ScanningState

 void tryToStartNewScan() {
            ...
            if (mScannerImpl.startSingleScan(settings, this)) {
                // 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());
                // notify and cancel failed scans
                sendOpFailedToAllAndClear(mPendingScans, WifiScanner.REASON_UNSPECIFIED,
                        "Failed to start single scan");
            }
        }

2.4.6 前面说到发了一个WifiScanner.CMD_GET_SINGLE_SCAN_RESULTS消息交给SingleScanStateMachine状态机处理
这边现在已经是ScanningState,所以就由ScanningState处理获取扫描结果的WifiScanner.CMD_GET_SINGLE_SCAN_RESULTS消息。

ScanningState无法处理该消息,上抛给父类DefaultState状态处理。

        class DefaultState extends State {
            @Override
            public void enter() {
                mActiveScans.clear();
                mPendingScans.clear();
            }
            @Override
            public boolean processMessage(Message msg) {
                switch (msg.what) {
                    case CMD_DRIVER_LOADED:
                        transitionTo(mIdleState);
                        return HANDLED;
                    case CMD_DRIVER_UNLOADED:
                        transitionTo(mDefaultState);
                        return HANDLED;
                    case WifiScanner.CMD_START_SINGLE_SCAN:
                    case WifiScanner.CMD_STOP_SINGLE_SCAN:
                        replyFailed(msg, WifiScanner.REASON_UNSPECIFIED, "not available");
                        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);
            }
        }

        /**
         * Maximum age of results that we return from our cache via
         * {@link WifiScanner#getScanResults()}.
         * This is currently set to 3 minutes to restore parity with the wpa_supplicant's scan
         * result cache expiration policy. (See b/62253332 for details)
         */
        @VisibleForTesting
        public static final int CACHED_SCAN_RESULTS_MAX_AGE_IN_MILLIS = 180 * 1000;

可以看到最终是从mCachedScanResults得到扫描结果。
那么mCachedScanResults这个缓存的数据是从哪里来的?如何更新的呢?
……………………………………………………………………………………
2.4.7 在WifiScanningService服务启动后会构建一个 WificondScannerImpl 的binder对象保存到ServiceManger中。
同时mWificondScanner注册了一个Scan的Event Callback: mScanEventHandler
frameworks/opt/net/wifi/service/java/com/android/server/wifi/WificondControl.java

    /**
    * Setup driver for client mode via wificond.
    * @return An IClientInterface as wificond client interface binder handler.
    * Returns null on failure.
    */
    public IClientInterface setupDriverForClientMode() {
        Log.d(TAG, "Setting up driver for client mode");
        mWificond = mWifiInjector.makeWificond();
        if (mWificond == null) {
            Log.e(TAG, "Failed to get reference to wificond");
            return null;
        }

        IClientInterface clientInterface = null;
        try {
            clientInterface = mWificond.createClientInterface();
        } catch (RemoteException e1) {
            Log.e(TAG, "Failed to get IClientInterface due to remote exception");
            return null;
        }

        if (clientInterface == null) {
            Log.e(TAG, "Could not get IClientInterface instance from wificond");
            return null;
        }
        Binder.allowBlocking(clientInterface.asBinder());

        // Refresh Handlers
        mClientInterface = clientInterface;
        try {
            mClientInterfaceName = clientInterface.getInterfaceName();
            mWificondScanner = mClientInterface.getWifiScannerImpl();
            if (mWificondScanner == null) {
                Log.e(TAG, "Failed to get WificondScannerImpl");
                return null;
            }
            Binder.allowBlocking(mWificondScanner.asBinder());
            mScanEventHandler = new ScanEventHandler();
            mWificondScanner.subscribeScanEvents(mScanEventHandler);
            mPnoScanEventHandler = new PnoScanEventHandler();
            mWificondScanner.subscribePnoScanEvents(mPnoScanEventHandler);
        } catch (RemoteException e) {
            Log.e(TAG, "Failed to refresh wificond scanner due to remote exception");
        }

        return clientInterface;
    }

看看这句:mScanEventHandler = new ScanEventHandler();
mScanEventHandler就是在这里创建的,mScanEventHandler是一个Binder对象,当有Scan数据的时候底层通过调用mScanEventHandler的OnScanResultReady函数告诉Framework层有Wifi扫描的数据了。

system/connectivity/wificond/scanning/scanner_impl.cpp

void ScannerImpl::OnScanResultsReady(uint32_t interface_index, bool aborted,
                                     vector<vector<uint8_t>>& ssids,
                                     vector<uint32_t>& frequencies) {
  if (!scan_started_) {
    LOG(INFO) << "Received external scan result notification from kernel.";
  }
  scan_started_ = false;
  if (scan_event_handler_ != nullptr) {
    // TODO: Pass other parameters back once we find framework needs them.
    if (aborted) {
      LOG(WARNING) << "Scan aborted";
      scan_event_handler_->OnScanFailed();
    } else {
      scan_event_handler_->OnScanResultReady();
    }
  } else {
    LOG(WARNING) << "No scan event handler found.";
  }
}

mScanEventHandler的OnScanResultReady函数:

这个函数就是直接调用了mWifiMonitor的broadcastScanResultEvent函数:

frameworks/opt/net/wifi/service/java/com/android/server/wifi/WificondControl.java

    private class ScanEventHandler extends IScanEvent.Stub {
        @Override
        public void OnScanResultReady() {
            Log.d(TAG, "Scan result ready event");
            mWifiMonitor.broadcastScanResultEvent(mClientInterfaceName);
        }

frameworks/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);
    }

broadcastScanResultEvent比较简单,就是向WifiMonitor发送了一个消息 SCAN_RESULTS_EVENT
WifiMinitor最终会把这个消息发送到 WifiScanningServiceImpl的消息队列里面来。为什么呢?看看下面的分析
在mScannerImpl的构建过程中(也就是WificondScannerImpl构造函数中)会向WifiMonitor中注册一个Handler:具体如下:

 public WificondScannerImpl(Context context, WifiNative wifiNative,
                                     WifiMonitor wifiMonitor, ChannelHelper channelHelper,
                                     Looper looper, Clock clock) {
        mContext = context;
        mWifiNative = wifiNative;
        mChannelHelper = channelHelper;
        mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
        mEventHandler = new Handler(looper, this);
        mClock = clock;
        mHwPnoDebouncer = new HwPnoDebouncer(mWifiNative, mAlarmManager, mEventHandler, mClock);

        // Check if the device supports HW PNO scans.
        mHwPnoScanSupported = mContext.getResources().getBoolean(
                R.bool.config_wifi_background_scan_support);

        wifiMonitor.registerHandler(mWifiNative.getInterfaceName(),
                WifiMonitor.SCAN_FAILED_EVENT, mEventHandler);
        wifiMonitor.registerHandler(mWifiNative.getInterfaceName(),
                WifiMonitor.PNO_SCAN_RESULTS_EVENT, mEventHandler);
        wifiMonitor.registerHandler(mWifiNative.getInterfaceName(),
                WifiMonitor.SCAN_RESULTS_EVENT, mEventHandler);
    }

1.mEventHandler = new Handler(looper, this);
首先在WificondScannerImpl构造函数中新建了一个Handler
2在前面的broadcastScanResultEvent中已经广播了一个SCAN_RESULTS_EVENT消息,这样WifiMonitor就知道了有SCAN_RESULTS_EVENT这么一个消息了
.wifiMonitor.registerHandler(mWifiNative.getInterfaceName(), WifiMonitor.SCAN_RESULTS_EVENT, mEventHandler);
这段代码的意思就是,向WifiMonitor中注册一个Handler,让WifiMonitor如果知道有WifiMonitor.SCAN_RESULTS_EVENT消息,就用 mEventHandler 发送WifiMonitor.SCAN_RESULTS_EVENT消息;WificondScannerImpl中的Handler发送的WifiMonitor.SCAN_RESULTS_EVENT消息,自然是由 WificondScannerImpl的handleMessage函数来处理。

所以WifiMonitor.SCAN_RESULTS_EVENT这个消息最终是由WificondScannerImpl来处理的
frameworks/opt/net/wifi/service/java/com/android/server/wifi/scanner/WificondScannerImpl.java

 public WificondScannerImpl(Context context, WifiNative wifiNative,
                                     WifiMonitor wifiMonitor, ChannelHelper channelHelper,
                                     Looper looper, Clock clock) {
   ...
    @Override
    public boolean handleMessage(Message msg) {
        switch(msg.what) {
            case WifiMonitor.SCAN_FAILED_EVENT:
                Log.w(TAG, "Scan failed");
                mAlarmManager.cancel(mScanTimeoutListener);
                reportScanFailure();
                processPendingScans();
                break;
            case WifiMonitor.PNO_SCAN_RESULTS_EVENT:
                pollLatestScanDataForPno();
                processPendingScans();
                break;
            case WifiMonitor.SCAN_RESULTS_EVENT:
                mAlarmManager.cancel(mScanTimeoutListener);
                pollLatestScanData();
                processPendingScans();
                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;
            }

            if (DBG) Log.d(TAG, "Polling scan data for scan: " + mLastScanSettings.scanId);
            mNativeScanResults = mWifiNative.getScanResults();
            List<ScanResult> singleScanResults = new ArrayList<>();
            List<ScanResult> backgroundScanResults = 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.backgroundScanActive) {
                        backgroundScanResults.add(result);
                    }
                    if (mLastScanSettings.singleScanActive
                            && mLastScanSettings.singleScanFreqs.containsChannel(
                                    result.frequency)) {
                        singleScanResults.add(result);
                    }
                }

             ...

            if (mLastScanSettings.singleScanActive
                    && 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(mLastScanSettings.scanId, 0, 0,
                        isAllChannelsScanned(mLastScanSettings.singleScanFreqs),
                        singleScanResults.toArray(new ScanResult[singleScanResults.size()]));
                mLastScanSettings.singleScanEventHandler
                        .onScanStatus(WifiNative.WIFI_SCAN_RESULTS_AVAILABLE);
            }

            mLastScanSettings = null;
        }
    }

这个函数主要做了如下几件事情:

1 调用mWifiNative.getScanResults();获取扫描结果:nativeResults

2 循环处理后把扫描结果保存到singleScanResults

3 把得到的singleScanResults保存到mLatestSingleScanResult中,最后调用singleScanEventHandler的onScanStatus函数通知framework层处理。

这里singleScanEventHandler 就是 WifiScanningServiceImpl

frameworks/opt/net/wifi/service/java/com/android/server/wifi/scanner/WifiScanningServiceImpl.java

        /**
         * Called to indicate a change in state for the current scan.
         * Will dispatch a coresponding event to the state machine
         */
        @Override
        public void onScanStatus(int event) {
            if (DBG) localLog("onScanStatus event received, event=" + event);
            switch(event) {
                case WifiNative.WIFI_SCAN_RESULTS_AVAILABLE:
                case WifiNative.WIFI_SCAN_THRESHOLD_NUM_SCANS:
                case WifiNative.WIFI_SCAN_THRESHOLD_PERCENT:
                    sendMessage(CMD_SCAN_RESULTS_AVAILABLE);
                    break;
                case WifiNative.WIFI_SCAN_FAILED:
                    sendMessage(CMD_SCAN_FAILED);
                    break;
                default:
                    Log.e(TAG, "Unknown scan status event: " + event);
                    break;
            }
        }

发送了一个消息sendMessage(CMD_SCAN_RESULTS_AVAILABLE);因为此时我们还是在ScanningState

 class ScanningState extends State {
 ...
       public boolean processMessage(Message msg) {
                switch (msg.what) {
                    case CMD_SCAN_RESULTS_AVAILABLE:
                        mWifiMetrics.incrementScanReturnEntry(
                                WifiMetricsProto.WifiLog.SCAN_SUCCESS,
                                mActiveScans.size());
                        reportScanResults(mScannerImpl.getLatestSingleScanResults());
                        mActiveScans.clear();
                        transitionTo(mIdleState);
                        return HANDLED;

reportScanResults(mScannerImpl.getLatestSingleScanResults());就是上报扫描结果了
最后都会调用到WificondScannerImpl的getLatestSingleScanResults方法

    @Override
    public WifiScanner.ScanData getLatestSingleScanResults() {
        return mLatestSingleScanResult;
    }

       void reportScanResults(ScanData results) {
            if (results != null && results.getResults() != null) {
                if (results.getResults().length > 0) {
                    mWifiMetrics.incrementNonEmptyScanResultCount();
                } else {
                    mWifiMetrics.incrementEmptyScanResultCount();
                }
            }
            ScanData[] allResults = new ScanData[] {results};
            for (RequestInfo<ScanSettings> entry : mActiveScans) {
                ScanData[] resultsToDeliver = ScanScheduleUtil.filterResultsForSettings(
                        mChannelHelper, allResults, entry.settings, -1);
                WifiScanner.ParcelableScanData parcelableResultsToDeliver =
                        new WifiScanner.ParcelableScanData(resultsToDeliver);
                logCallback("singleScanResults",  entry.clientInfo, entry.handlerId,
                        describeForLog(resultsToDeliver));
                entry.reportEvent(WifiScanner.CMD_SCAN_RESULT, 0, parcelableResultsToDeliver);
                // make sure the handler is removed
                entry.reportEvent(WifiScanner.CMD_SINGLE_SCAN_COMPLETED, 0, null);
            }

            WifiScanner.ParcelableScanData parcelableAllResults =
                    new WifiScanner.ParcelableScanData(allResults);
            for (RequestInfo<Void> entry : mSingleScanListeners) {
                logCallback("singleScanResults",  entry.clientInfo, entry.handlerId,
                        describeForLog(allResults));
                entry.reportEvent(WifiScanner.CMD_SCAN_RESULT, 0, parcelableAllResults);
            }

            if (results.isAllChannelsScanned()) {
                mCachedScanResults.clear();
                mCachedScanResults.addAll(Arrays.asList(results.getResults()));
                sendScanResultBroadcast(true);
            }
        }

可以看到这里就是对mCachedScanResults这个集合做增减操作了。将传进的mScannerImpl.getLatestSingleScanResults()添加到mCachedScanResults中: mCachedScanResults.addAll(Arrays.asList(results.getResults()));如此我们便吧2.4.6中最后遗留的问题点解决了

前面说到pollLatestScanData主要做了三件事
1 调用mWifiNative.getScanResults();获取扫描结果:nativeResults

2 循环处理后把扫描结果保存到singleScanResults

3 把得到的singleScanResults保存到mLatestSingleScanResult中,最后调用singleScanEventHandler的onScanStatus函数通知framework层reportScanResults处理。
我们现在是把扫描结果nativeResults添加到mCachedScanResults中了,但是nativeResults又是怎么得到的呢?下面我们一起来看看

2.4.8 WifiNative

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

    /**
     * Fetch the latest scan result from kernel via wificond.
     * @return Returns an ArrayList of ScanDetail.
     * Returns an empty ArrayList on failure.
     */
    public ArrayList<ScanDetail> getScanResults() {
        return mWificondControl.getScanResults(WificondControl.SCAN_TYPE_SINGLE_SCAN);
    }

2..4.9 WificondControl

framework/opt/net/wifi/service/java/com/android/server/wifi/WificondControl.java

    /**
    * Fetch the latest scan result from kernel via wificond.
    * @return Returns an ArrayList of ScanDetail.
    * Returns an empty ArrayList on failure.
    */
    public ArrayList<ScanDetail> getScanResults(int scanType) {
        ArrayList<ScanDetail> results = new ArrayList<>();
        if (mWificondScanner == null) {
            Log.e(TAG, "No valid wificond scanner interface handler");
            return results;
        }
        try {
            NativeScanResult[] nativeResults;
            if (scanType == SCAN_TYPE_SINGLE_SCAN) {
                nativeResults = mWificondScanner.getScanResults();
            } else {
                nativeResults = mWificondScanner.getPnoScanResults();
            }
            for (NativeScanResult result : nativeResults) {
                WifiSsid wifiSsid = WifiSsid.createFromByteArray(result.ssid);
                String bssid;
                try {
                    bssid = NativeUtil.macAddressFromByteArray(result.bssid);
                } catch (IllegalArgumentException e) {
                    Log.e(TAG, "Illegal argument " + result.bssid, e);
                    continue;
                }
                if (bssid == null) {
                    Log.e(TAG, "Illegal null bssid");
                    continue;
                }
                ScanResult.InformationElement[] ies =
                        InformationElementUtil.parseInformationElements(result.infoElement);
                InformationElementUtil.Capabilities capabilities =
                        new InformationElementUtil.Capabilities();
                capabilities.from(ies, result.capability);
                String flags = capabilities.generateCapabilitiesString();
                NetworkDetail networkDetail;
                try {
                    networkDetail = new NetworkDetail(bssid, ies, null, result.frequency);
                } catch (IllegalArgumentException e) {
                    Log.e(TAG, "Illegal argument for scan result with bssid: " + bssid, e);
                    continue;
                }

                ScanDetail scanDetail = new ScanDetail(networkDetail, wifiSsid, bssid, flags,
                        result.signalMbm / 100, result.frequency, result.tsf, ies, null);
                // Update carrier network info if this AP's SSID is associated with a carrier Wi-Fi
                // network and it uses EAP.
                if (ScanResultUtil.isScanResultForEapNetwork(scanDetail.getScanResult())
                        && mCarrierNetworkConfig.isCarrierNetwork(wifiSsid.toString())) {
                    scanDetail.getScanResult().isCarrierAp = true;
                    scanDetail.getScanResult().carrierApEapType =
                            mCarrierNetworkConfig.getNetworkEapType(wifiSsid.toString());
                    scanDetail.getScanResult().carrierName =
                            mCarrierNetworkConfig.getCarrierName(wifiSsid.toString());
                }
                results.add(scanDetail);
            }
        } catch (RemoteException e1) {
            Log.e(TAG, "Failed to create ScanDetail ArrayList");
        }
        if (mVerboseLoggingEnabled) {
            Log.d(TAG, "get " + results.size() + " scan results from wificond");
        }

        return results;
    }

2.4.10 scanner_impl

Status ScannerImpl::getScanResults(vector<NativeScanResult>* out_scan_results) {
  if (!CheckIsValid()) {
    return Status::ok();
  }
  if (!scan_utils_->GetScanResult(interface_index_, out_scan_results)) {
    LOG(ERROR) << "Failed to get scan results via NL80211";
  }
  return Status::ok();
}

2.4.11 scan_utils

bool ScanUtils::GetScanResult(uint32_t interface_index,
                              vector<NativeScanResult>* out_scan_results) {
  NL80211Packet get_scan(
      netlink_manager_->GetFamilyId(),
      NL80211_CMD_GET_SCAN,
      netlink_manager_->GetSequenceNumber(),
      getpid());
  get_scan.AddFlag(NLM_F_DUMP);
  NL80211Attr<uint32_t> ifindex(NL80211_ATTR_IFINDEX, interface_index);
  get_scan.AddAttribute(ifindex);

  vector<unique_ptr<const NL80211Packet>> response;
  if (!netlink_manager_->SendMessageAndGetResponses(get_scan, &response))  {
    LOG(ERROR) << "NL80211_CMD_GET_SCAN dump failed";
    return false;
  }
  if (response.empty()) {
    LOG(INFO) << "Unexpected empty scan result!";
    return true;
  }

  for (auto& packet : response) {
    if (packet->GetMessageType() == NLMSG_ERROR) {
      LOG(ERROR) << "Receive ERROR message: "
                 << strerror(packet->GetErrorCode());
      continue;
    }
    if (packet->GetMessageType() != netlink_manager_->GetFamilyId()) {
      LOG(ERROR) << "Wrong message type: "
                 << packet->GetMessageType();
      continue;
    }
    uint32_t if_index;
    if (!packet->GetAttributeValue(NL80211_ATTR_IFINDEX, &if_index)) {
      LOG(ERROR) << "No interface index in scan result.";
      continue;
    }
    if (if_index != interface_index) {
      LOG(WARNING) << "Uninteresting scan result for interface: " << if_index;
      continue;
    }

    NativeScanResult scan_result;
    if (!ParseScanResult(std::move(packet), &scan_result)) {
      LOG(DEBUG) << "Ignore invalid scan result";
      continue;
    }
    out_scan_results->push_back(std::move(scan_result));
  }
  return true;
}

3.总结
这里写图片描述

猜你喜欢

转载自blog.csdn.net/huangweiqing80/article/details/82458874