Android O WiFi的扫描流程

版权声明:本文为博主原创文章,未经博主允许不得转载。https://blog.csdn.net/huangweiqing80/article/details/82420977
在之前的分析中WIFI已经启动了,wpa_supplicant enabled,下面我们开始来分析wifi启动后是如何来扫描周围的AP的?
在Android O之前,wifi的扫描是通过frameworks层发命令到wifinative,再到hardware/libhardware_legacy/wifi/wifi.c,然后调用wpa_supplicant API,将scan的命令通过wpa_supplicant下发到kernel,但是在Android O中scan跟以前版本不同了

1.Android O的scan跟之前Android版本存在的差异

1) Android O开始scan的命令不是通过wpa_supplicant下发到kernel,而是直接由wificond传送到kernel,而scan results的结果也是直接由kernel传给wificond,再由wificond传送给上层去显示
2) 在framework层,现在scan改由scanner这个类去使用,之前从6.0开始慢慢用起来,现在到了8.0,可以说已经用了近95%了,剩下了目前google还在修改中,google的目标应该是想把scan整个完全独立出来,不跟其他的扯太大,例如WifiStateMachine
3) 目前上层下发的scan,已经改由SettingsLib去定时下,不交给apk去做了。
在android 8.0之前的版本,scan的定时扫描都是在上层app做的,但从8.0开始,google把这个定时器改到了framework中的SettingsLib(frameworks/base/packages/SettingsLib)中去了
4) 之前的版本scan操作,当同一时间下两次scan时,是直接交由wpa_supplicant去隔开的,现在由于直接把scan下发给kernel。所以,google已经把上层下的scan跟framework的自动scan也实现了分离,不让这两种flow打到,让同一时间只下一次scan,后一次则做pending动作

2. 流程分析

这里写图片描述

2.1 Settings

WiFi Settings在Android 8.0代码同样分为两部分,packages/apps/Settings和framework/base/packages/SettingsLib。

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

这里会调用到SettingsLib的WifiTracker,WifiTracker中包含了wifi扫描的操作。比较奇怪的是,这里没有走监听wifi打开消息,待WiFi打开后开始扫描,而是只要在WiFi界面就开始扫描了。不用奇怪,因为后面会去做检查只有wifi打开之后,才会真正下发scan命令到底层,具体请看下面的分析。

2.2 SettingsLib

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

扫描二维码关注公众号,回复: 3187947 查看本文章
    /**
     * Start tracking wifi networks and scores.
     *
     * <p>Registers listeners and starts scanning for wifi networks. If this is not called
     * then forceUpdate() must be called to populate getAccessPoints().
     */
    @MainThread
    public void startTracking() {
        synchronized (mLock) {
            registerScoreCache();

            mNetworkScoringUiEnabled =
                    Settings.Global.getInt(
                            mContext.getContentResolver(),
                            Settings.Global.NETWORK_SCORING_UI_ENABLED, 0) == 1;

            mMaxSpeedLabelScoreCacheAge =
                    Settings.Global.getLong(
                            mContext.getContentResolver(),
                            Settings.Global.SPEED_LABEL_CACHE_EVICTION_AGE_MILLIS,
                            DEFAULT_MAX_CACHED_SCORE_AGE_MILLIS);

            resumeScanning();
            if (!mRegistered) {
                mContext.registerReceiver(mReceiver, mFilter);
                // NetworkCallback objects cannot be reused. http://b/20701525 .
                mNetworkCallback = new WifiTrackerNetworkCallback();
                mConnectivityManager.registerNetworkCallback(mNetworkRequest, mNetworkCallback);
                mRegistered = true;
            }
        }
    }

startTracking() –> resumeScanning();

    /**
     * Resume scanning for wifi networks after it has been paused.
     *
     * <p>The score cache should be registered before this method is invoked.
     */
    public void resumeScanning() {
        if (mScanner == null) {
            mScanner = new Scanner();
        }

        mWorkHandler.sendEmptyMessage(WorkHandler.MSG_RESUME);
        if (mWifiManager.isWifiEnabled()) {
            mScanner.resume();
        }
    }

这里可以看到resumeScanning()会去判断wifi有没有打开mWifiManager.isWifiEnabled(),如果没有打开就不继续进行扫描流程了。只有打开了wifi才会调用mScanner.resume()继续走下去
frameworks/base/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java

    @VisibleForTesting
    class Scanner extends Handler {
        static final int MSG_SCAN = 0;

        private int mRetry = 0;

        void resume() {
            if (!hasMessages(MSG_SCAN)) {
                sendEmptyMessage(MSG_SCAN);
            }
        }

        void forceScan() {
            removeMessages(MSG_SCAN);
            sendEmptyMessage(MSG_SCAN);
        }

        void pause() {
            mRetry = 0;
            removeMessages(MSG_SCAN);
        }

        @VisibleForTesting
        boolean isScanning() {
            return hasMessages(MSG_SCAN);
        }

        @Override
        public void handleMessage(Message message) {
            if (message.what != MSG_SCAN) return;
            if (mWifiManager.startScan()) {
                mRetry = 0;
            } else if (++mRetry >= 3) {
                mRetry = 0;
                if (mContext != null) {
                    Toast.makeText(mContext, R.string.wifi_fail_to_scan, Toast.LENGTH_LONG).show();
                }
                return;
            }
            sendEmptyMessageDelayed(MSG_SCAN, WIFI_RESCAN_INTERVAL_MS);
        }
    }

class Scanner是WifiTracker中的一个内部类,整个类就这么一点代码,那么来分析一下这个Scanner类,前面调用的这个mScanner.resume()函数中就发送了一条消息sendEmptyMessage(MSG_SCAN);然后在类中的handleMessage中对这个消息进行处理,这个类的handleMessage中也只处理这一个消息,从handleMessage函数中可以看到if (message.what != MSG_SCAN) return;如果不是MSG_SCAN就退出函数了,如果是才会接着去进行扫描。
这里可以看到如果扫描失败3次就会导致扫描失败的toast的提醒,如果扫描成功则会进行扫描间隔为10s的持续扫描。

   // TODO: Allow control of this?
    // Combo scans can take 5-6s to complete - set to 10s.
    private static final int WIFI_RESCAN_INTERVAL_MS = 10 * 1000;

从mWifiManager.startScan()可以知道,这里扫描流程就走到WifiManager里去了

2.3 WiFi framework

2.3.1 WifiManager

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

    /**
     * Request a scan for access points. Returns immediately. The availability
     * of the results is made known later by means of an asynchronous event sent
     * on completion of the scan.
     * @return {@code true} if the operation succeeded, i.e., the scan was initiated
     */
    public boolean startScan() {
        return startScan(null);
    }

    /** @hide */
    @SystemApi
    @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS)
    public boolean startScan(WorkSource workSource) {
        try {
            String packageName = mContext.getOpPackageName();
            mService.startScan(null, workSource, packageName);
            return true;
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

从代码角度来看startScan要么返回true要么抛异常呀,false不可能。。。

之前分析过mService对应的服务端是WifiServiceImpl

2.3.2 WifiServiceImpl

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

 /**
     * see {@link android.net.wifi.WifiManager#startScan}
     * and {@link android.net.wifi.WifiManager#startCustomizedScan}
     *
     * @param settings If null, use default parameter, i.e. full scan.
     * @param workSource If null, all blame is given to the calling uid.
     * @param packageName Package name of the app that requests wifi scan.
     */
    @Override
    public void startScan(ScanSettings settings, WorkSource workSource, String packageName) {
        enforceChangePermission();

        mLog.info("startScan uid=%").c(Binder.getCallingUid()).flush();
        // Check and throttle background apps for wifi scan.
        if (isRequestFromBackground(packageName)) {
            long lastScanMs = mLastScanTimestamps.getOrDefault(packageName, 0L);
            long elapsedRealtime = mClock.getElapsedSinceBootMillis();

            if (lastScanMs != 0 && (elapsedRealtime - lastScanMs) < mBackgroundThrottleInterval) {
                sendFailedScanBroadcast();
                return;
            }
            // Proceed with the scan request and record the time.
            mLastScanTimestamps.put(packageName, elapsedRealtime);
        }
        synchronized (this) {
            if (mWifiScanner == null) {
                mWifiScanner = mWifiInjector.getWifiScanner();
            }
            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;
            }
        }
        if (settings != null) {
            settings = new ScanSettings(settings);
            if (!settings.isValid()) {
                Slog.e(TAG, "invalid scan setting");
                return;
            }
        }
        if (workSource != null) {
            enforceWorkSourcePermission();
            // WifiManager currently doesn't use names, so need to clear names out of the
            // supplied WorkSource to allow future WorkSource combining.
            workSource.clearNames();
        }
        if (workSource == null && Binder.getCallingUid() >= 0) {
            workSource = new WorkSource(Binder.getCallingUid());
        }
        mWifiStateMachine.startScan(Binder.getCallingUid(), scanRequestCounter++,
                settings, workSource);
    }

注意这个方法前两个参数传进来的都是null,这边一开始会对wifi扫描的请求对象做个过滤,毕竟WiFi扫描是耗电的,不能谁都来请求一下。不在白名单的后台应用的请求扫描时间间隔如果短于30min,则通报批评。下面是startScan函数中对此过滤的操作和分析

        // Check and throttle background apps for wifi scan.
        if (isRequestFromBackground(packageName)) {
            long lastScanMs = mLastScanTimestamps.getOrDefault(packageName, 0L);
            long elapsedRealtime = mClock.getElapsedSinceBootMillis();

            if (lastScanMs != 0 && (elapsedRealtime - lastScanMs) < mBackgroundThrottleInterval) {
                sendFailedScanBroadcast();
                return;
            }
            // Proceed with the scan request and record the time.
            mLastScanTimestamps.put(packageName, elapsedRealtime);
        }

isRequestFromBackground函数源码如下:

    // Check if the request comes from background.
    private boolean isRequestFromBackground(String packageName) {
        // Requests from system or wifi are not background.
        if (Binder.getCallingUid() == Process.SYSTEM_UID
                || Binder.getCallingUid() == Process.WIFI_UID) {
            return false;
        }
        mAppOps.checkPackage(Binder.getCallingUid(), packageName);
        if (mBackgroundThrottlePackageWhitelist.contains(packageName)) {
            return false;
        }

        // getPackageImportance requires PACKAGE_USAGE_STATS permission, so clearing the incoming
        // identify so the permission check can be done on system process where wifi runs in.
        long callingIdentity = Binder.clearCallingIdentity();
        try {
            return mActivityManager.getPackageImportance(packageName)
                    > BACKGROUND_IMPORTANCE_CUTOFF;
        } finally {
            Binder.restoreCallingIdentity(callingIdentity);
        }
    }

扫描间隔DEFAULT_SCAN_BACKGROUND_THROTTLE_INTERVAL_MS定义如下

    private static final long DEFAULT_SCAN_BACKGROUND_THROTTLE_INTERVAL_MS = 30 * 60 * 1000;

sendFailedScanBroadcast函数源码如下

    // Send a failed scan broadcast to indicate the current scan request failed.
    private void sendFailedScanBroadcast() {
        // clear calling identity to send broadcast
        long callingIdentity = Binder.clearCallingIdentity();
        try {
            Intent intent = new Intent(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
            intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
            intent.putExtra(WifiManager.EXTRA_RESULTS_UPDATED, false);
            mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
        } finally {
            // restore calling identity
            Binder.restoreCallingIdentity(callingIdentity);
        }

    }

回到刚才的startScan函数。由于传入的前两个参数是null,则直接走到WifiStateMachine里去了。

        mWifiStateMachine.startScan(Binder.getCallingUid(), scanRequestCounter++,
                settings, workSource);

2.3.3 WifiStateMachine

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

    /**
     * Initiate a wifi scan. If workSource is not null, blame is given to it, otherwise blame is
     * given to callingUid.
     *
     * @param callingUid The uid initiating the wifi scan. Blame will be given here unless
     *                   workSource is specified.
     * @param workSource If not null, blame is given to workSource.
     * @param settings   Scan settings, see {@link ScanSettings}.
     */
    public void startScan(int callingUid, int scanCounter,
                          ScanSettings settings, WorkSource workSource) {
        Bundle bundle = new Bundle();
        bundle.putParcelable(CUSTOMIZED_SCAN_SETTING, settings);
        bundle.putParcelable(CUSTOMIZED_SCAN_WORKSOURCE, workSource);
        bundle.putLong(SCAN_REQUEST_TIME, mClock.getWallClockMillis());
        sendMessage(CMD_START_SCAN, callingUid, scanCounter, bundle);
    }

sendMessage(CMD_START_SCAN, callingUid, scanCounter, bundle);发送一条消息CMD_START_SCAN;
由于前面已经enable supplicant,所以到目前扫描阶段,WifiStateMachine状态机目前的状态应该是SupplicantStartedState,下面来看看WifiStateMachine在SupplicantStartedState 怎么处理这个消息

    class SupplicantStartedState extends State {
         ...
            @Override
        public boolean processMessage(Message message) {
            logStateAndMessage(message, this);

            switch(message.what) {
                ...
                case CMD_START_SCAN:
                    // TODO: remove scan request path (b/31445200)
                    handleScanRequest(message);
                    break;

调用handleScanRequest(message);进行处理

    private void handleScanRequest(Message message) {
        ScanSettings settings = null;
        WorkSource workSource = null;

        // unbundle parameters
        Bundle bundle = (Bundle) message.obj;

        if (bundle != null) {
            settings = bundle.getParcelable(CUSTOMIZED_SCAN_SETTING);
            workSource = bundle.getParcelable(CUSTOMIZED_SCAN_WORKSOURCE);
        }

        Set<Integer> freqs = null;
        if (settings != null && settings.channelSet != null) {
            freqs = new HashSet<>();
            for (WifiChannel channel : settings.channelSet) {
                freqs.add(channel.freqMHz);
            }
        }

        // Retrieve the list of hidden network SSIDs to scan for.
        List<WifiScanner.ScanSettings.HiddenNetwork> hiddenNetworks =
                mWifiConfigManager.retrieveHiddenNetworkList();

        // call wifi native to start the scan
        if (startScanNative(freqs, hiddenNetworks, workSource)) {
            // a full scan covers everything, clearing scan request buffer
            if (freqs == null)
                mBufferedScanMsg.clear();
            messageHandlingStatus = MESSAGE_HANDLING_STATUS_OK;
            return;
        }

        // if reach here, scan request is rejected

        if (!mIsScanOngoing) {
            // if rejection is NOT due to ongoing scan (e.g. bad scan parameters),

            // discard this request and pop up the next one
            if (mBufferedScanMsg.size() > 0) {
                sendMessage(mBufferedScanMsg.remove());
            }
            messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD;
        } else if (!mIsFullScanOngoing) {
            // if rejection is due to an ongoing scan, and the ongoing one is NOT a full scan,
            // buffer the scan request to make sure specified channels will be scanned eventually
            if (freqs == null)
                mBufferedScanMsg.clear();
            if (mBufferedScanMsg.size() < SCAN_REQUEST_BUFFER_MAX_SIZE) {
                Message msg = obtainMessage(CMD_START_SCAN,
                        message.arg1, message.arg2, bundle);
                mBufferedScanMsg.add(msg);
            } else {
                // if too many requests in buffer, combine them into a single full scan
                bundle = new Bundle();
                bundle.putParcelable(CUSTOMIZED_SCAN_SETTING, null);
                bundle.putParcelable(CUSTOMIZED_SCAN_WORKSOURCE, workSource);
                Message msg = obtainMessage(CMD_START_SCAN, message.arg1, message.arg2, bundle);
                mBufferedScanMsg.clear();
                mBufferedScanMsg.add(msg);
            }
            messageHandlingStatus = MESSAGE_HANDLING_STATUS_LOOPED;
        } else {
            // mIsScanOngoing and mIsFullScanOngoing
            messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
        }
    }

if (startScanNative(freqs, hiddenNetworks, workSource))
继续调用startScanNative

   // TODO this is a temporary measure to bridge between WifiScanner and WifiStateMachine until
    // scan functionality is refactored out of WifiStateMachine.
    /**
     * return true iff scan request is accepted
     */
    private boolean startScanNative(final Set<Integer> freqs,
            List<WifiScanner.ScanSettings.HiddenNetwork> hiddenNetworkList,
            WorkSource workSource) {
        WifiScanner.ScanSettings settings = new WifiScanner.ScanSettings();
        if (freqs == null) {
            settings.band = WifiScanner.WIFI_BAND_BOTH_WITH_DFS;
        } else {
            settings.band = WifiScanner.WIFI_BAND_UNSPECIFIED;
            int index = 0;
            settings.channels = new WifiScanner.ChannelSpec[freqs.size()];
            for (Integer freq : freqs) {
                settings.channels[index++] = new WifiScanner.ChannelSpec(freq);
            }
        }
        settings.reportEvents = WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN
                | WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT;

        settings.hiddenNetworks =
                hiddenNetworkList.toArray(
                        new WifiScanner.ScanSettings.HiddenNetwork[hiddenNetworkList.size()]);

        WifiScanner.ScanListener nativeScanListener = new WifiScanner.ScanListener() {
                // ignore all events since WifiStateMachine is registered for the supplicant events
                @Override
                public void onSuccess() {
                }
                @Override
                public void onFailure(int reason, String description) {
                    mIsScanOngoing = false;
                    mIsFullScanOngoing = false;
                }
                @Override
                public void onResults(WifiScanner.ScanData[] results) {
                }
                @Override
                public void onFullResult(ScanResult fullScanResult) {
                }
                @Override
                public void onPeriodChanged(int periodInMs) {
                }
            };
        mWifiScanner.startScan(settings, nativeScanListener, workSource);
        mIsScanOngoing = true;
        mIsFullScanOngoing = (freqs == null);
        lastScanFreqs = freqs;
        return true;
    }

由于freqs和workSource这两个参数为null,走settings.band = WifiScanner.WIFI_BAND_BOTH_WITH_DFS;所以settings.band是7,即频段为7

    /** Both 2.4 GHz band and 5 GHz band; with DFS channels */
    public static final int WIFI_BAND_BOTH_WITH_DFS = 7;    /* both bands with DFS channels */

这边继续调用WifiScanner的startScan,settings不是null了,已经在startScanNative函数中被默认初始化过了。另外
WifiScanner.ScanListener nativeScanListener = new WifiScanner.ScanListener()
这边初始化了一个nativeScanListener委托给WifiScanner,从方法来看是有结果了会回调这个Listner,使用了委托模式。

2.3.4 WifiScanner

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

    /**
     * starts a single scan and reports results asynchronously
     * @param settings specifies various parameters for the scan; for more information look at
     * {@link ScanSettings}
     * @param listener specifies the object to report events to. This object is also treated as a
     *                 key for this scan, and must also be specified to cancel the scan. Multiple
     *                 scans should also not share this object.
     */
    @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
    public void startScan(ScanSettings settings, ScanListener listener) {
        startScan(settings, listener, null);
    }

    /**
     * starts a single scan and reports results asynchronously
     * @param settings specifies various parameters for the scan; for more information look at
     * {@link ScanSettings}
     * @param workSource WorkSource to blame for power usage
     * @param listener specifies the object to report events to. This object is also treated as a
     *                 key for this scan, and must also be specified to cancel the scan. Multiple
     *                 scans should also not share this object.
     */
    @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
    public void startScan(ScanSettings settings, ScanListener listener, WorkSource workSource) {
        Preconditions.checkNotNull(listener, "listener cannot be null");
        int key = addListener(listener);
        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);
        mAsyncChannel.sendMessage(CMD_START_SINGLE_SCAN, 0, key, scanParams);
    }

这里用了AsyncChannel,和aidl一样,也是IPC的一种方式。其实WifiScanner对应的服务端就是WifiScanningServiceImpl

下面来分析一下为什么WifiScanner对应的服务端就是WifiScanningServiceImpl,看一WifiScanner的构造函数

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

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

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

        mAsyncChannel = new AsyncChannel();

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

从WifiScanner的构造方法里可以看到InternalHandler/AsyncChannel/Messenger是完成IPC的桥梁。

另外WifiScanner的初始化是经由WifiStateMachine在WifiInjector里完成的。

            // We can't do this in the constructor because WifiStateMachine is created before the
            // wifi scanning service is initialized
            if (mWifiScanner == null) {
                mWifiScanner = mWifiInjector.getWifiScanner();

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

    /**
     * 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;
    }

先看下在SystemServer会启动WifiScanningService服务

                traceBeginAndSlog("StartWifiScanning");
                mSystemServiceManager.startService(
                        "com.android.server.wifi.scanner.WifiScanningService");
                traceEnd();

再看下WifiScanningService这个服务

public class WifiScanningService extends SystemService {

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

    public WifiScanningService(Context context) {
        super(context);
        Log.i(TAG, "Creating " + Context.WIFI_SCANNING_SERVICE);
        mHandlerThread = new HandlerThread("WifiScanningService");
        mHandlerThread.start();
        mImpl = new WifiScanningServiceImpl(getContext(), mHandlerThread.getLooper(),
                WifiScannerImpl.DEFAULT_FACTORY, BatteryStatsService.getService(),
                WifiInjector.getInstance());
    }
    @Override
    public void onStart() {
        Log.i(TAG, "Publishing " + Context.WIFI_SCANNING_SERVICE);
        publishBinderService(Context.WIFI_SCANNING_SERVICE, mImpl);
    }

    /**
     * Publish the service so it is accessible to other services and apps.
     */
    protected final void publishBinderService(String name, IBinder service) {
        publishBinderService(name, service, false);
    }

    /**
     * Publish the service so it is accessible to other services and apps.
     */
    protected final void publishBinderService(String name, IBinder service,
            boolean allowIsolated) {
        ServiceManager.addService(name, service, allowIsolated);
    }

果不其然和WifiService一个套路,里面会new WifiScanningServiceImpl,经由SystemService的publishBinderService将自己加入到ServiceManager管理的Service中去,那么这里WifiScanner对应的服务端就是WifiScanningServiceImpl了。

现在就从WifiScanner进入到WifiScanningServiceImpl了

2.3.5 WifiScanningServiceImpl

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

继而再看下getMessenger方法:

@Override
public Messenger getMessenger() {
    if (mClientHandler != null) {
        mLog.trace("getMessenger() uid=%").c(Binder.getCallingUid()).flush();
        return new Messenger(mClientHandler);
    }
    loge("WifiScanningServiceImpl trying to get messenger w/o initialization");
    return null;
}

这里梳理出来WifiScanningServiceImpl的ClientHander是处理WifiScanner发出的CMD_START_SINGLE_SCAN消息
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) {
               ...
                case WifiScanner.CMD_START_SINGLE_SCAN:
                case WifiScanner.CMD_STOP_SINGLE_SCAN:
                    mSingleScanStateMachine.sendMessage(Message.obtain(msg));
                    break;
        mSingleScanStateMachine = new WifiSingleScanStateMachine(mLooper);

这里又是状态模式,其中有个DriverStartedState继续处理,
framework/opt/net/wifi/service/java/com/android/server/wifi/scanner/WifiScanningServiceImpl.java

        /**
         * State representing when the driver is running. This state is not meant to be transitioned
         * directly, but is instead indented as a parent state of ScanningState and IdleState
         * to hold common functionality and handle cleaning up scans when the driver is shut down.
         */
        class DriverStartedState extends State {
            @Override
            public void exit() {
                // clear scan results when scan mode is not active
                mCachedScanResults.clear();

                mWifiMetrics.incrementScanReturnEntry(
                        WifiMetricsProto.WifiLog.SCAN_FAILURE_INTERRUPTED,
                        mPendingScans.size());
                sendOpFailedToAllAndClear(mPendingScans, WifiScanner.REASON_UNSPECIFIED,
                        "Scan was interrupted");
            }

            @Override
            public boolean processMessage(Message msg) {
                ClientInfo ci = mClients.get(msg.replyTo);

                switch (msg.what) {
                    case WifiScanner.CMD_START_SINGLE_SCAN:
                        mWifiMetrics.incrementOneshotScanCount();
                        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 HANDLED;
                        }
                        scanParams.setDefusable(true);
                        ScanSettings scanSettings =
                                scanParams.getParcelable(WifiScanner.SCAN_PARAMS_SCAN_SETTINGS_KEY);
                        WorkSource workSource =
                                scanParams.getParcelable(WifiScanner.SCAN_PARAMS_WORK_SOURCE_KEY);
                        if (validateScanRequest(ci, handler, scanSettings, workSource)) {
                            logScanRequest("addSingleScanRequest", ci, handler, workSource,
                                    scanSettings, null);
                            replySucceeded(msg);

                            // 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 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.
                            if (getCurrentState() == mScanningState) {
                                if (activeScanSatisfies(scanSettings)) {
                                    mActiveScans.addRequest(ci, handler, workSource, scanSettings);
                                } else {
                                    mPendingScans.addRequest(ci, handler, workSource, scanSettings);
                                }
                            } else {
                                mPendingScans.addRequest(ci, handler, workSource, scanSettings);
                                tryToStartNewScan();
                            }
                        } else {
                            logCallback("singleScanInvalidRequest",  ci, handler, "bad request");
                            replyFailed(msg, WifiScanner.REASON_INVALID_REQUEST, "bad request");
                            mWifiMetrics.incrementScanReturnEntry(
                                    WifiMetricsProto.WifiLog.SCAN_FAILURE_INVALID_CONFIGURATION, 1);
                        }
                        return HANDLED;

这里可以看到对上了,把我们千辛万苦传来的参数取了出来,虽然workSource就是个null,但是scanSettings的band是7

                    ScanSettings scanSettings =
                            scanParams.getParcelable(WifiScanner.SCAN_PARAMS_SCAN_SETTINGS_KEY);
                    WorkSource workSource =
                            scanParams.getParcelable(WifiScanner.SCAN_PARAMS_WORK_SOURCE_KEY);

之后返回一个操作成功的消息replySucceeded(msg);但这并不是搜索成功了,这里还没进行搜索scan;返回消息之后才会真正去进行搜索,

    void replySucceeded(Message msg) {
        if (msg.replyTo != null) {
            Message reply = Message.obtain();
            reply.what = WifiScanner.CMD_OP_SUCCEEDED;
            reply.arg2 = msg.arg2;
            if (msg.obj != null) {
                reply.obj = msg.obj;
            }
            try {
                msg.replyTo.send(reply);
                mLog.trace("replySucceeded recvdMessage=%").c(msg.what).flush();
            } catch (RemoteException e) {
                // There's not much we can do if reply can't be sent!
            }
        } else {
            // locally generated message; doesn't need a reply!
        }
    }

这边WifiScanner的ServiceHandler会收到并处理
frameworks/base/wifi/java/android/net/wifi/WifiScanner.java

    private class ServiceHandler extends Handler {
        ServiceHandler(Looper looper) {
            super(looper);
        }
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED:
                    return;
                case AsyncChannel.CMD_CHANNEL_DISCONNECTED:
                    Log.e(TAG, "Channel connection lost");
                    // This will cause all further async API calls on the WifiManager
                    // to fail and throw an exception
                    mAsyncChannel = null;
                    getLooper().quit();
                    return;
            }

            Object listener = getListener(msg.arg2);

            if (listener == null) {
                if (DBG) Log.d(TAG, "invalid listener key = " + msg.arg2);
                return;
            } else {
                if (DBG) Log.d(TAG, "listener key = " + msg.arg2);
            }

            switch (msg.what) {
                    /* ActionListeners grouped together */
                case CMD_OP_SUCCEEDED :
                    ((ActionListener) listener).onSuccess();
                    break;

最后再调用到我们在WifiStateMachine里初始化好的listener的success方法,但是这里是空的
frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiStateMachine.java

        WifiScanner.ScanListener nativeScanListener = new WifiScanner.ScanListener() {
                // ignore all events since WifiStateMachine is registered for the supplicant events
                @Override
                public void onSuccess() {
                }
                @Override
                public void onFailure(int reason, String description) {
                    mIsScanOngoing = false;
                    mIsFullScanOngoing = false;
                }
                @Override
                public void onResults(WifiScanner.ScanData[] results) {
                }
                @Override
                public void onFullResult(ScanResult fullScanResult) {
                }
                @Override
                public void onPeriodChanged(int periodInMs) {
                }
            };

接着前面的DriverStartedState进行分析返回操作成功消息返回一个操作成功的消息replySucceeded(msg);之后的代码如下
framework/opt/net/wifi/service/java/com/android/server/wifi/scanner/WifiScanningServiceImpl.java

                            replySucceeded(msg);

                            // 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 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.
                            if (getCurrentState() == mScanningState) {
                                if (activeScanSatisfies(scanSettings)) {
                                    mActiveScans.addRequest(ci, handler, workSource, scanSettings);
                                } else {
                                    mPendingScans.addRequest(ci, handler, workSource, scanSettings);
                                }
                            } else {
                                mPendingScans.addRequest(ci, handler, workSource, scanSettings);
                                tryToStartNewScan();
                            }
                        } else {
                            logCallback("singleScanInvalidRequest",  ci, handler, "bad request");
                            replyFailed(msg, WifiScanner.REASON_INVALID_REQUEST, "bad request");
                            mWifiMetrics.incrementScanReturnEntry(
                                    WifiMetricsProto.WifiLog.SCAN_FAILURE_INVALID_CONFIGURATION, 1);
                        }
                        return HANDLED;

这边代码意思是如果正在搜索那么就不重新开始新的scan了,否则tryToStartNewScan()

然后看下tryToStartNewScan()
framework/opt/net/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) {
                channels.addChannels(entry.settings);
                if (entry.settings.hiddenNetworks != null) {
                    for (int i = 0; i < entry.settings.hiddenNetworks.length; i++) {
                        WifiNative.HiddenNetwork hiddenNetwork = new WifiNative.HiddenNetwork();
                        hiddenNetwork.ssid = entry.settings.hiddenNetworks[i].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 (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 (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");
            }
        }

重点看mScannerImpl.startSingleScan

先看一下mScannerImpl是怎么来的
framework/opt/net/wifi/service/java/com/android/server/wifi/scanner/WifiScanningServiceImpl.java

    private WifiScannerImpl mScannerImpl;
    mScannerImpl = mScannerImplFactory.create(mContext, mLooper, mClock);

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

public abstract class WifiScannerImpl {

    /**
     * A factory that create a {@link com.android.server.wifi.scanner.WifiScannerImpl}
     */
    public static interface WifiScannerImplFactory {
        WifiScannerImpl create(Context context, Looper looper, Clock clock);
    }

    /**
     * Factory that create the implementation that is most appropriate for the system.
     * This factory should only ever be used once.
     */
    public static final WifiScannerImplFactory DEFAULT_FACTORY = new WifiScannerImplFactory() {
            public WifiScannerImpl create(Context context, Looper looper, Clock clock) {
                WifiNative wifiNative = WifiInjector.getInstance().getWifiNative();
                WifiMonitor wifiMonitor = WifiInjector.getInstance().getWifiMonitor();
                if (wifiNative.getBgScanCapabilities(new WifiNative.ScanCapabilities())) {
                    return new HalWifiScannerImpl(context, wifiNative, wifiMonitor, looper, clock);
                } else {
                    return new WificondScannerImpl(context, wifiNative, wifiMonitor, looper,
                            clock);
                }
            }
        };

从mScannerImpl = mScannerImplFactory.create(mContext, mLooper, mClock);知道。
mScannerImpl是通过factory创建出来的,那么这个factory是如何创建的?mScannerImplFactory是怎么来的?
先来看一下WifiScanningService
frameworks/opt/net/wifi/service/java/com/android/server/wifi/scanner/WifiScanningService.java

        mImpl = new WifiScanningServiceImpl(getContext(), mHandlerThread.getLooper(),
                WifiScannerImpl.DEFAULT_FACTORY, BatteryStatsService.getService(),
                WifiInjector.getInstance());

再看一下WifiScanningServiceImpl的构造函数
frameworks/opt/net/wifi/service/java/com/android/server/wifi/scanner/WifiScanningService.java

    WifiScanningServiceImpl(Context context, Looper looper,
            WifiScannerImpl.WifiScannerImplFactory scannerImplFactory, IBatteryStats batteryStats,
            WifiInjector wifiInjector) {
        mContext = context;
        mLooper = looper;
        mScannerImplFactory = scannerImplFactory;
        mBatteryStats = batteryStats;
        mClients = new ArrayMap<>();
        mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
        mWifiMetrics = wifiInjector.getWifiMetrics();
        mClock = wifiInjector.getClock();
        mLog = wifiInjector.makeLog(TAG);
        mFrameworkFacade = wifiInjector.getFrameworkFacade();
        mPreviousSchedule = null;
    }

原来mScannerImplFactory是通过new WifiScanningServiceImpl创建的参数,然后在WifiScanningServiceImpl构造函数中赋值的mScannerImplFactory = scannerImplFactory;我们可以看到fmScannerImplFactory其实就是WifiScannerImpl.DEFAULT_FACTORY
frameworks/opt/net/wifi/service/java/com/android/server/wifi/scanner/WifiScannerImpl.java

    public static final WifiScannerImplFactory DEFAULT_FACTORY = new WifiScannerImplFactory() {
            public WifiScannerImpl create(Context context, Looper looper, Clock clock) {
                WifiNative wifiNative = WifiInjector.getInstance().getWifiNative();
                WifiMonitor wifiMonitor = WifiInjector.getInstance().getWifiMonitor();
                if (wifiNative.getBgScanCapabilities(new WifiNative.ScanCapabilities())) {
                    return new HalWifiScannerImpl(context, wifiNative, wifiMonitor, looper, clock);
                } else {
                    return new WificondScannerImpl(context, wifiNative, wifiMonitor, looper,
                            clock);
                }
            }
        };

可以看到里面返回的是对象HalWifiScannerImpl或者WificondScannerImpl,所以前面的mScannerImpl.startSingleScan其实调用的是这两个对象的startSingleScan方法
分别看下这两个对象实现的HalWifiScannerImpl.startSingleScan方法

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

    public boolean startSingleScan(WifiNative.ScanSettings settings,
            WifiNative.ScanEventHandler eventHandler) {
        return mWificondScannerDelegate.startSingleScan(settings, eventHandler);
    }
        mWificondScannerDelegate =
                new WificondScannerImpl(context, wifiNative, wifiMonitor, mChannelHelper,
                        looper, clock);

所以HalWifiScannerImpl.startSingleScan其实就是WificondScannerImpl.startSingleScan
所以前面的mScannerImpl.startSingleScan其实真正调用的是WificondScannerImpl.startSingleScan

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

    @Override
    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;
        }
        if (mPendingSingleScanSettings != null
                || (mLastScanSettings != null && mLastScanSettings.singleScanActive)) {
            Log.w(TAG, "A single scan is already running");
            return false;
        }
        synchronized (mSettingsLock) {
            mPendingSingleScanSettings = settings;
            mPendingSingleScanEventHandler = eventHandler;
            processPendingScans();
            return true;
        }
    }
    private void processPendingScans() {
        synchronized (mSettingsLock) {
            // Wait for the active scan result to come back to reschedule other scans,
            // unless if HW pno scan is running. Hw PNO scans are paused it if there
            // are other pending scans,
            if (mLastScanSettings != null && !mLastScanSettings.hwPnoScanActive) {
                return;
            }

            ChannelCollection allFreqs = mChannelHelper.createChannelCollection();
            Set<String> hiddenNetworkSSIDSet = new HashSet<>();
            final LastScanSettings newScanSettings =
                    new LastScanSettings(mClock.getElapsedSinceBootMillis());

            // Update scan settings if there is a pending scan
            if (!mBackgroundScanPaused) {
                if (mPendingBackgroundScanSettings != null) {
                    mBackgroundScanSettings = mPendingBackgroundScanSettings;
                    mBackgroundScanEventHandler = mPendingBackgroundScanEventHandler;
                    mNextBackgroundScanPeriod = 0;
                    mPendingBackgroundScanSettings = null;
                    mPendingBackgroundScanEventHandler = null;
                    mBackgroundScanPeriodPending = true;
                }
                if (mBackgroundScanPeriodPending && mBackgroundScanSettings != null) {
                    int reportEvents = WifiScanner.REPORT_EVENT_NO_BATCH; // default to no batch
                    for (int bucket_id = 0; bucket_id < mBackgroundScanSettings.num_buckets;
                            ++bucket_id) {
                        WifiNative.BucketSettings bucket =
                                mBackgroundScanSettings.buckets[bucket_id];
                        if (mNextBackgroundScanPeriod % (bucket.period_ms
                                        / mBackgroundScanSettings.base_period_ms) == 0) {
                            if ((bucket.report_events
                                            & WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN) != 0) {
                                reportEvents |= WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN;
                            }
                            if ((bucket.report_events
                                            & WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT) != 0) {
                                reportEvents |= WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT;
                            }
                            // only no batch if all buckets specify it
                            if ((bucket.report_events
                                            & WifiScanner.REPORT_EVENT_NO_BATCH) == 0) {
                                reportEvents &= ~WifiScanner.REPORT_EVENT_NO_BATCH;
                            }

                            allFreqs.addChannels(bucket);
                        }
                    }
                    if (!allFreqs.isEmpty()) {
                        newScanSettings.setBackgroundScan(mNextBackgroundScanId++,
                                mBackgroundScanSettings.max_ap_per_scan, reportEvents,
                                mBackgroundScanSettings.report_threshold_num_scans,
                                mBackgroundScanSettings.report_threshold_percent);
                    }
                    mNextBackgroundScanPeriod++;
                    mBackgroundScanPeriodPending = false;
                    mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
                            mClock.getElapsedSinceBootMillis()
                                    + mBackgroundScanSettings.base_period_ms,
                            BACKGROUND_PERIOD_ALARM_TAG, mScanPeriodListener, mEventHandler);
                }
            }

            if (mPendingSingleScanSettings != null) {
                boolean reportFullResults = false;
                ChannelCollection singleScanFreqs = mChannelHelper.createChannelCollection();
                for (int i = 0; i < mPendingSingleScanSettings.num_buckets; ++i) {
                    WifiNative.BucketSettings bucketSettings =
                            mPendingSingleScanSettings.buckets[i];
                    if ((bucketSettings.report_events
                                    & WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT) != 0) {
                        reportFullResults = true;
                    }
                    singleScanFreqs.addChannels(bucketSettings);
                    allFreqs.addChannels(bucketSettings);
                }
                newScanSettings.setSingleScan(reportFullResults, singleScanFreqs,
                        mPendingSingleScanEventHandler);

                WifiNative.HiddenNetwork[] hiddenNetworks =
                        mPendingSingleScanSettings.hiddenNetworks;
                if (hiddenNetworks != null) {
                    int numHiddenNetworks =
                            Math.min(hiddenNetworks.length, MAX_HIDDEN_NETWORK_IDS_PER_SCAN);
                    for (int i = 0; i < numHiddenNetworks; i++) {
                        hiddenNetworkSSIDSet.add(hiddenNetworks[i].ssid);
                    }
                }

                mPendingSingleScanSettings = null;
                mPendingSingleScanEventHandler = null;
            }

            if (newScanSettings.backgroundScanActive || newScanSettings.singleScanActive) {
                boolean success = false;
                Set<Integer> freqs;
                if (!allFreqs.isEmpty()) {
                    pauseHwPnoScan();
                    freqs = allFreqs.getScanFreqs();
                    success = mWifiNative.scan(freqs, hiddenNetworkSSIDSet);
                    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 for");
                }
                if (success) {
                    // TODO handle scan timeout
                    if (DBG) {
                        Log.d(TAG, "Starting wifi scan for freqs=" + freqs
                                + ", background=" + newScanSettings.backgroundScanActive
                                + ", single=" + newScanSettings.singleScanActive);
                    }
                    mLastScanSettings = newScanSettings;
                    mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
                            mClock.getElapsedSinceBootMillis() + SCAN_TIMEOUT_MS,
                            TIMEOUT_ALARM_TAG, mScanTimeoutListener, mEventHandler);
                } else {
                    // indicate scan failure async
                    mEventHandler.post(new Runnable() {
                            public void run() {
                                if (newScanSettings.singleScanEventHandler != null) {
                                    newScanSettings.singleScanEventHandler
                                            .onScanStatus(WifiNative.WIFI_SCAN_FAILED);
                                }
                            }
                        });
                    // TODO(b/27769665) background scans should be failed too if scans fail enough
                }
            } else if (isHwPnoScanRequired()) {
                newScanSettings.setHwPnoScan(mPnoSettings.networkList, mPnoEventHandler);
                boolean status;
                // If the PNO network list has changed from the previous request, ensure that
                // we bypass the debounce logic and restart PNO scan.
                if (isDifferentPnoScanSettings(newScanSettings)) {
                    status = restartHwPnoScan(mPnoSettings);
                } else {
                    status = startHwPnoScan(mPnoSettings);
                }
                if (status) {
                    mLastScanSettings = newScanSettings;
                } else {
                    Log.e(TAG, "Failed to start PNO scan");
                    // indicate scan failure async
                    mEventHandler.post(new Runnable() {
                        public void run() {
                            if (mPnoEventHandler != null) {
                                mPnoEventHandler.onPnoScanFailed();
                            }
                            // Clean up PNO state, we don't want to continue PNO scanning.
                            mPnoSettings = null;
                            mPnoEventHandler = null;
                        }
                    });
                }
            }
        }
    }

代码很长的,但我们重点看下面这一句
success = mWifiNative.scan(freqs, hiddenNetworkSSIDSet);
最终还是会调用到WifiNative的scan方法,毕竟上层的搜索都是空的,还要底层配合。

2.3.7 WifiNative
frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiNative.java

    /**
     * Start a scan using wificond for the given parameters.
     * @param freqs list of frequencies to scan for, if null scan all supported channels.
     * @param hiddenNetworkSSIDs List of hidden networks to be scanned for.
     * @return Returns true on success.
     */
    public boolean scan(Set<Integer> freqs, Set<String> hiddenNetworkSSIDs) {
        return mWificondControl.scan(freqs, hiddenNetworkSSIDs);
    }

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

    /**
     * Start a scan using wificond for the given parameters.
     * @param freqs list of frequencies to scan for, if null scan all supported channels.
     * @param hiddenNetworkSSIDs List of hidden networks to be scanned for.
     * @return Returns true on success.
     */
    public boolean scan(Set<Integer> freqs, Set<String> hiddenNetworkSSIDs) {
        if (mWificondScanner == null) {
            Log.e(TAG, "No valid wificond scanner interface handler");
            return false;
        }
        SingleScanSettings settings = new SingleScanSettings();
        settings.channelSettings  = new ArrayList<>();
        settings.hiddenNetworks  = new ArrayList<>();

        if (freqs != null) {
            for (Integer freq : freqs) {
                ChannelSettings channel = new ChannelSettings();
                channel.frequency = freq;
                settings.channelSettings.add(channel);
            }
        }
        if (hiddenNetworkSSIDs != null) {
            for (String ssid : hiddenNetworkSSIDs) {
                HiddenNetwork network = new HiddenNetwork();
                try {
                    network.ssid = NativeUtil.byteArrayFromArrayList(NativeUtil.decodeSsid(ssid));
                } catch (IllegalArgumentException e) {
                    Log.e(TAG, "Illegal argument " + ssid, e);
                    continue;
                }
                settings.hiddenNetworks.add(network);
            }
        }

        try {
            return mWificondScanner.scan(settings);
        } catch (RemoteException e1) {
            Log.e(TAG, "Failed to request scan due to remote exception");
        }
        return false;
    }

这边又调用到WificondScanner里去了,下面来看一下mWificondScanner是怎么来的,是在setupDriverForClientMode函数中赋值得到的

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;
    }

我们把上面的代码重点抽取出来


    public IClientInterface setupDriverForClientMode() {

        mWificond = mWifiInjector.makeWificond();


            clientInterface = mWificond.createClientInterface();

        // Refresh Handlers
        mClientInterface = clientInterface;

            mWificondScanner = mClientInterface.getWifiScannerImpl();

    }

原来mWificondScanner = mClientInterface.getWifiScannerImpl();是这么来的
这里就涉及到java与c++之间的aidl-cpp通信。我们有空再慢慢梳理
2.4 Native
这里写图片描述
这里我们先到代码中搜一下getWifiScannerImpl方法实现,这里看到只有client_interface_binder.cpp有对应实现
system/connectivity/wificond/client_interface_binder.cpp

Status ClientInterfaceBinder::getWifiScannerImpl(
    sp<IWifiScannerImpl>* out_wifi_scanner_impl) {
  if (impl_ == nullptr) {
    *out_wifi_scanner_impl = nullptr;
    return Status::ok();
  }
  *out_wifi_scanner_impl = impl_->GetScanner();
  return Status::ok();
}

所以mWificondScanner = mClientInterface.getWifiScannerImpl();最终一定会调用到client_interface_binder.cpp中的ClientInterfaceBinder::getWifiScannerImpl
这里我们知道传入的参数是IWifiScannerImpl的实现类,而impl_是ClientInterfaceImpl对象。
这里我们主要关注*out_wifi_scanner_impl = impl_->GetScanner();

而GetScanner方法:
system/connectivity/wificond/client_interface_impl.h

  const android::sp<ScannerImpl> GetScanner() { return scanner_; };

直接返回scanner_

  android::sp<ScannerImpl> scanner_;

看来scanner_是一个ScannerImpl对象
看下ScannerImpl这个类的scan方法
system/connectivity/wificond/scanning/scanner_impl.cpp

Status ScannerImpl::scan(const SingleScanSettings& scan_settings,
                         bool* out_success) {
  if (!CheckIsValid()) {
    *out_success = false;
    return Status::ok();
  }

  if (scan_started_) {
    LOG(WARNING) << "Scan already started";
  }
  // Only request MAC address randomization when station is not associated.
  bool request_random_mac = wiphy_features_.supports_random_mac_oneshot_scan &&
                            !client_interface_->IsAssociated();

  // Initialize it with an empty ssid for a wild card scan.
  vector<vector<uint8_t>> ssids = {{}};

  vector<vector<uint8_t>> skipped_scan_ssids;
  for (auto& network : scan_settings.hidden_networks_) {
    if (ssids.size() + 1 > scan_capabilities_.max_num_scan_ssids) {
      skipped_scan_ssids.emplace_back(network.ssid_);
      continue;
    }
    ssids.push_back(network.ssid_);
  }

  LogSsidList(skipped_scan_ssids, "Skip scan ssid for single scan");

  vector<uint32_t> freqs;
  for (auto& channel : scan_settings.channel_settings_) {
    freqs.push_back(channel.frequency_);
  }

  int error_code = 0;
  if (!scan_utils_->Scan(interface_index_, request_random_mac, ssids, freqs,
                         &error_code)) {
    CHECK(error_code != ENODEV) << "Driver is in a bad state, restarting wificond";
    *out_success = false;
    return Status::ok();
  }
  scan_started_ = true;
  *out_success = true;
  return Status::ok();
}

可以看到这里会调用到scan_utils方法:
scan_utils_->Scan(interface_index_, request_random_mac, ssids, freqs,
&error_code)

2.5 scan_utils.cpp

bool ScanUtils::Scan(uint32_t interface_index,
                     bool request_random_mac,
                     const vector<vector<uint8_t>>& ssids,
                     const vector<uint32_t>& freqs,
                     int* error_code) {
  NL80211Packet trigger_scan(
      netlink_manager_->GetFamilyId(),
      NL80211_CMD_TRIGGER_SCAN,
      netlink_manager_->GetSequenceNumber(),
      getpid());
  // If we do not use NLM_F_ACK, we only receive a unicast repsonse
  // when there is an error. If everything is good, scan results notification
  // will only be sent through multicast.
  // If NLM_F_ACK is set, there will always be an unicast repsonse, either an
  // ERROR or an ACK message. The handler will always be called and removed by
  // NetlinkManager.
  trigger_scan.AddFlag(NLM_F_ACK);
  NL80211Attr<uint32_t> if_index_attr(NL80211_ATTR_IFINDEX, interface_index);


  NL80211NestedAttr ssids_attr(NL80211_ATTR_SCAN_SSIDS);
  for (size_t i = 0; i < ssids.size(); i++) {
    ssids_attr.AddAttribute(NL80211Attr<vector<uint8_t>>(i, ssids[i]));
  }
  NL80211NestedAttr freqs_attr(NL80211_ATTR_SCAN_FREQUENCIES);
  for (size_t i = 0; i < freqs.size(); i++) {
    freqs_attr.AddAttribute(NL80211Attr<uint32_t>(i, freqs[i]));
  }


  trigger_scan.AddAttribute(if_index_attr);
  trigger_scan.AddAttribute(ssids_attr);
  // An absence of NL80211_ATTR_SCAN_FREQUENCIES attribue informs kernel to
  // scan all supported frequencies.
  if (!freqs.empty()) {
    trigger_scan.AddAttribute(freqs_attr);
  }


  if (request_random_mac) {
    trigger_scan.AddAttribute(
        NL80211Attr<uint32_t>(NL80211_ATTR_SCAN_FLAGS,
                              NL80211_SCAN_FLAG_RANDOM_ADDR));
  }
  // We are receiving an ERROR/ACK message instead of the actual
  // scan results here, so it is OK to expect a timely response because
  // kernel is supposed to send the ERROR/ACK back before the scan starts.
  vector<unique_ptr<const NL80211Packet>> response;
  if (!netlink_manager_->SendMessageAndGetAckOrError(trigger_scan,
                                                     error_code)) {
    // Logging is done inside |SendMessageAndGetAckOrError|.
    return false;
  }
  if (*error_code != 0) {
    LOG(ERROR) << "NL80211_CMD_TRIGGER_SCAN failed: " << strerror(*error_code);
    return false;
  }
  return true;
}

我们可以看到 netlink_manager_->SendMessageAndGetAckOrError这个函数把trigger_scan中的NL80211_CMD_TRIGGER_SCAN下发给kernel,并从等到应答

2.6 netlink_manager.cpp

bool NetlinkManager::SendMessageAndGetAckOrError(const NL80211Packet& packet,
                                                 int* error_code) {
  unique_ptr<const NL80211Packet> response;
  if (!SendMessageAndGetSingleResponseOrError(packet, &response)) {
    return false;
  }
  uint16_t type = response->GetMessageType();
  if (type != NLMSG_ERROR) {
    LOG(ERROR) << "Receive unexpected message type :" << type;
    return false;
  }

  *error_code = response->GetErrorCode();
  return true;
}

bool NetlinkManager::SendMessageAndGetSingleResponseOrError(
    const NL80211Packet& packet,
    unique_ptr<const NL80211Packet>* response) {
  vector<unique_ptr<const NL80211Packet>> response_vec;
  if (!SendMessageAndGetResponses(packet, &response_vec)) {
    return false;**重点内容**
  }
  if (response_vec.size() != 1) {
    LOG(ERROR) << "Unexpected response size: " << response_vec.size();
    return false;
  }

  *response = std::move(response_vec[0]);
  return true;
}

bool NetlinkManager::SendMessageAndGetResponses(
    const NL80211Packet& packet,
    vector<unique_ptr<const NL80211Packet>>* response) {
  if (!SendMessageInternal(packet, sync_netlink_fd_.get())) {
    return false;
  }
  // Polling netlink socket, waiting for GetFamily reply.
  struct pollfd netlink_output;
  memset(&netlink_output, 0, sizeof(netlink_output));
  netlink_output.fd = sync_netlink_fd_.get();
  netlink_output.events = POLLIN;

  uint32_t sequence = packet.GetMessageSequence();

  int time_remaining = kMaximumNetlinkMessageWaitMilliSeconds;
  // Multipart messages may come with seperated datagrams, ending with a
  // NLMSG_DONE message.
  // ReceivePacketAndRunHandler() will remove the handler after receiving a
  // NLMSG_DONE message.
  message_handlers_[sequence] = std::bind(AppendPacket, response, _1);

  while (time_remaining > 0 &&
      message_handlers_.find(sequence) != message_handlers_.end()) {
    nsecs_t interval = systemTime(SYSTEM_TIME_MONOTONIC);
    int poll_return = poll(&netlink_output,
                           1,
                           time_remaining);

    if (poll_return == 0) {
      LOG(ERROR) << "Failed to poll netlink fd: time out ";
      message_handlers_.erase(sequence);
      return false;
    } else if (poll_return == -1) {
      LOG(ERROR) << "Failed to poll netlink fd: " << strerror(errno);
      message_handlers_.erase(sequence);
      return false;
    }
    ReceivePacketAndRunHandler(sync_netlink_fd_.get());
    interval = systemTime(SYSTEM_TIME_MONOTONIC) - interval;
    time_remaining -= static_cast<int>(ns2ms(interval));
  }
  if (time_remaining <= 0) {
    LOG(ERROR) << "Timeout waiting for netlink reply messages";
    message_handlers_.erase(sequence);
    return false;
  }
  return true;
}

bool NetlinkManager::SendMessageInternal(const NL80211Packet& packet, int fd) {
  const vector<uint8_t>& data = packet.GetConstData();
  ssize_t bytes_sent =
      TEMP_FAILURE_RETRY(send(fd, data.data(), data.size(), 0));
  if (bytes_sent == -1) {
    LOG(ERROR) << "Failed to send netlink message: " << strerror(errno);
    return false;
  }
  return true;
}

3.总结
这里写图片描述

参考:https://blog.csdn.net/sinat_20059415/article/details/80784129
https://blog.csdn.net/gh201030460222/article/details/80553645

猜你喜欢

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