(五十) Android O WiFi的扫描流程梳理

前言:在之前的WiFi博客中主要梳理了WiFi的启动流程,WiFi启动后给人最直观的感觉就是开始扫描出周围的AP了,那扫描流程是怎么样的呢?


aosp : android O


1. WiFi扫描流程简介

wifi的扫描流程和启动流程一样,也是设置将扫描命令下发到framework,再往下我就不大梳理地下去了,所以本篇梳理也是Settings+framework组合的模式开始梳理。Settings在Android 8.0代码同样分为两部分,packages/apps/Settings和framework/base/packages/SettingsLib。至于为什么SettingsLib不放在packages/apps/Settings下呢,我理解是代码共享的考虑,SystemUi和开机向导中的蓝牙WiFi流程也会用到对应代码。


2. 流程分析

Settings+SettingsLib+framework

2.1 Settings

/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界面就开始扫描了。


2.2 SettingsLib

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

扫描二维码关注公众号,回复: 1794779 查看本文章
    /**
     * 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;
            }
        }
    }
    /**
     * 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有没有打开,如果没有打开就不继续进行扫描流程了。

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

这里可以看到如果扫描失败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;

这里扫描流程就走到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,则通报批评=-=
        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);
        }

    // 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 throttling interval if not overriden in settings
    private static final long DEFAULT_SCAN_BACKGROUND_THROTTLE_INTERVAL_MS = 30 * 60 * 1000;
    // 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);
        }

    }

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

        if (workSource == null && Binder.getCallingUid() >= 0) {
            workSource = new WorkSource(Binder.getCallingUid());
        }
        mWifiStateMachine.startScan(Binder.getCallingUid(), scanRequestCounter++,
                settings, workSource);

    // Debug counter tracking scan requests sent by WifiManager
    private int scanRequestCounter = 0;


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

SupplicantStartedState 会处理这个消息

                case CMD_START_SCAN:
                    // TODO: remove scan request path (b/31445200)
                    handleScanRequest(message);
                    break;
    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;
        }
    }
继续调用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是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了,已经被默认初始化过了。另外这边初始化了一个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的一种方式。

    /**
     * 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的服务启动

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

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

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


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;
    }
AsyncChannel的机理忘了差不多了,后面补一下,这里梳理出来WifiScanningServiceImpl的ClientHander是处理WifiScanner发出的CMD_START_SINGLE_SCAN消息

                case WifiScanner.CMD_START_SINGLE_SCAN:
                case WifiScanner.CMD_STOP_SINGLE_SCAN:
                    mSingleScanStateMachine.sendMessage(Message.obtain(msg));
                    break;
        mSingleScanStateMachine = new WifiSingleScanStateMachine(mLooper);
其中有个DriverStartedState继续处理,这里又是状态模式。
        /**
         * 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);

之后返回一个搜索成功的消息

    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会收到并处理

            switch (msg.what) {
                    /* ActionListeners grouped together */
                case CMD_OP_SUCCEEDED :
                    ((ActionListener) listener).onSuccess();
最后再调用到我们在WifiStateMachine里初始化好的listener的success方法,虽然是个空的=-=

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

之后会和WifiStateMachine的状态扯上关系

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

        boolean activeScanSatisfies(ScanSettings settings) {
            if (mActiveScanSettings == null) {
                return false;
            }

            // there is always one bucket for a single scan
            WifiNative.BucketSettings activeBucket = mActiveScanSettings.buckets[0];

            // validate that all requested channels are being scanned
            ChannelCollection activeChannels = mChannelHelper.createChannelCollection();
            activeChannels.addChannels(activeBucket);
            if (!activeChannels.containsSettings(settings)) {
                return false;
            }

            // if the request is for a full scan, but there is no ongoing full scan
            if ((settings.reportEvents & WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT) != 0
                    && (activeBucket.report_events & WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT)
                    == 0) {
                return false;
            }

            if (!ArrayUtils.isEmpty(settings.hiddenNetworks)) {
                if (ArrayUtils.isEmpty(mActiveScanSettings.hiddenNetworks)) {
                    return false;
                }
                List<WifiNative.HiddenNetwork> activeHiddenNetworks = new ArrayList<>();
                for (WifiNative.HiddenNetwork hiddenNetwork : mActiveScanSettings.hiddenNetworks) {
                    activeHiddenNetworks.add(hiddenNetwork);
                }
                for (ScanSettings.HiddenNetwork hiddenNetwork : settings.hiddenNetworks) {
                    WifiNative.HiddenNetwork nativeHiddenNetwork = new WifiNative.HiddenNetwork();
                    nativeHiddenNetwork.ssid = hiddenNetwork.ssid;
                    if (!activeHiddenNetworks.contains(nativeHiddenNetwork)) {
                        return false;
                    }
                }
            }

            return true;
        }
没梳理完,待续。。。怎么感觉流程是对的,但是功能没了,只剩个架子了。。。

------------------------------------------------------------6月24日更新------------------------------------------------------------

参考了https://blog.csdn.net/xiaoxiangyuhai/article/details/75159403

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

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

然后看下tryToStartNewScan()

        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

看下这是个啥:

    private WifiScannerImpl mScannerImpl;
    mScannerImpl = mScannerImplFactory.create(mContext, mLooper, mClock);
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);
                }
            }
        };

接着看下这个factory如何创建的

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

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

这里可以看到factory用的是默认实现WifiScannerImpl.DEFAULT_FACTORY

                if (wifiNative.getBgScanCapabilities(new WifiNative.ScanCapabilities())) {
                    return new HalWifiScannerImpl(context, wifiNative, wifiMonitor, looper, clock);
                } else {
                    return new WificondScannerImpl(context, wifiNative, wifiMonitor, looper,
                            clock);
                }

分别看下这两个实现的startSingleScan方法

1. HalWifiScannerImpl

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

2.WificondScannerImpl:这边发现调用到最后两个实现调到一起去了。


2.3.6 WificondScannerImpl

    @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

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

    /**
     * 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里去了,看下是啥

    /**
    * 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;
    }
这边的几步看不下去了。。。
        mWificond = mWifiInjector.makeWificond();
    public IWificond makeWificond() {
        // We depend on being able to refresh our binder in WifiStateMachine, so don't cache it.
        IBinder binder = ServiceManager.getService(WIFICOND_SERVICE_NAME);
        return IWificond.Stub.asInterface(binder);
    }
            clientInterface = mWificond.createClientInterface();
            mWificondScanner = mClientInterface.getWifiScannerImpl();
感觉要到驱动层了=-=
待续。。。

搜了下

./system/connectivity/wificond/aidl/android/net/wifi/IWifiScannerImpl.aidl

./system/connectivity/wificond/aidl/android/net/wifi/IWificond.aidl


---------------------------------------------------------6月27日更新---------------------------------------------------------

请教下了,这块Wificond对应的服务端确实是放在system/connectivity下面,是cpp文件,逻辑是从之前的wpa_supplicant里迁出来的

---------------------------------------------------------6月27日更新---------------------------------------------------------


猜你喜欢

转载自blog.csdn.net/sinat_20059415/article/details/80784129