[转载] Wifi模块—源码分析Wifi热点扫描(Android P)

[转载] Wifi模块—源码分析Wifi热点扫描(Android P),第1张

概述原文链接:https://blog.csdn.net/weixin_42093428/article/details/82682804一前言    这次接着讲Wifi工程流程中的Wifi热点查找过程,也是Wifi启动的过程延续,Wifi启动过程中会更新Wifi的状态,框架层也有相应广播发出,应用层接收到广播后开始 原文链接:https://blog.csdn.net/weixin_42093428/article/details/82682804一 前言

       这次接着讲Wifi工程流程中的Wifi热点查找过程,也是Wifi启动的过程延续,Wifi启动过程中会更新Wifi的状态,框架层也有相应广播发出,应用层接收到广播后开始进行热点的扫描。可以先看前面Wifi启动的分析过程。

                               Wifi模块源码分析Wifi启动1(Android P)

                               Wifi模块—源码分析Wifi启动2(Android P)

 

二 图示调用流程

      由于在 frameworks/base/packages/Settingslib/src/com/androID/settingslib/wifi/WifiTracker.java直接接收到框架层发出的wifi状态改变的广播WIFI_STATE_CHANGED_ACTION(这个在后面有交待),所以这里的图示调用流程将从WifiTracker.java开始。

三 代码具体流程

       我们先回顾一下之前wifi启动过程的相关细节,wifi启动过程会走到ClIEntModeStateMachine这个状态机,具体看 Wifi模块—源码分析Wifi启动1(Android P)。

frameworks/opt/net/wifi/service/java/com/androID/server/wifi/ClIEntModeManager.java 

看ClIEntModeStateMachine的构造函数。

ClIEntModeStateMachine(Looper looper) {    super(TAG, looper);     addState(mIDleState);    addState(mStartedState);     setinitialState(mIDleState);    start();}

再看start()。

/*** Start clIEnt mode.*/public voID start() {    mStateMachine.sendMessage(ClIEntModeStateMachine.CMD_START);}

发送了一个消息ClIEntModeStateMachine.CMD_START。

private class IDleState extends State {     @OverrIDe    public voID enter() {        Log.d(TAG, "entering IDleState");        mClIEntInterfacename = null;        mIfaceIsUp = false;    }     @OverrIDe    public boolean processMessage(Message message) {        switch (message.what) {            case CMD_START:                updateWifiState(WifiManager.WIFI_STATE_ENABliNG,                                    WifiManager.WIFI_STATE_Disabled);                 mClIEntInterfacename = mWifiNative.setupInterfaceForClIEntMode(false /* not low priority */, mWifiNativeInterfaceCallback);                if (TextUtils.isEmpty(mClIEntInterfacename)) {                    Log.e(TAG, "Failed to create ClIEntInterface. Sit in IDle");                    updateWifiState(WifiManager.WIFI_STATE_UNKNowN,                                WifiManager.WIFI_STATE_ENABliNG);                    updateWifiState(WifiManager.WIFI_STATE_Disabled,                                        WifiManager.WIFI_STATE_UNKNowN);                    break;                }                sendScanAvailablebroadcast(false);                mScanRequestProxy.enableScanningForHIDdenNetworks(false);                mScanRequestProxy.clearScanResults();                TransitionTo(mStartedState);                break;            default:                Log.d(TAG, "received an invalID message: " + message);                return NOT_HANDLED;        }        return HANDLED;    }}

在IDleState的状态里接收到消息做相关处理updateWifiState,继续看这个方法。

/**     * Update Wifi state and send the broadcast.     * @param newState new Wifi state     * @param currentState current wifi state*/private voID updateWifiState(int newState, int currentState) {    if (!mExpectedStop) {        mListener.onStateChanged(newState);    } else {        Log.d(TAG, "expected stop, not triggering callbacks: newState = "            + newState);    }     // Once we report the mode has stopped/Failed any other stop signals are redundant    // note: this can happen in failure modes where we get multiple callbacks as underlying    // components/interface stops or the underlying interface is destroyed in cleanup    if (newState == WifiManager.WIFI_STATE_UNKNowN                || newState == WifiManager.WIFI_STATE_Disabled) {        mExpectedStop = true;    }     if (newState == WifiManager.WIFI_STATE_UNKNowN) {        // do not need to broadcast failure to system        return;    }     mWifiStateMachine.setWifiStateForAPICalls(newState);     final Intent intent = new Intent(WifiManager.WIFI_STATE_CHANGED_ACTION);    intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);    intent.putExtra(WifiManager.EXTRA_WIFI_STATE, newState);    intent.putExtra(WifiManager.EXTRA_PREVIoUS_WIFI_STATE, currentState);    mContext.sendStickybroadcastAsUser(intent, UserHandle.ALL);}

在这里发送了一个广播sendStickybroadcastAsUser,广播具体是WifiManager.WIFI_STATE_CHANGED_ACTION。

        OK,上面的分析都属于上次分析wifi启动的部分,就是wifi在启动过程中会更新wifi状态并发送wifi状态改变的广播。不过。上次在分析wifi启动过程中也没有分析这个更新wifi状态发送广播的这个内容,这次作为一个补充也是开启接下来的wifi热点扫描的流程分析,接下来的wifi扫描过程是指打开wifi之后自动扫描过程而不是手动去刷新扫描。

 

1 应用层

1.1 packages/apps/Settings/src/com/androID/settings/wifi/WifiSettings.java 

在WifiSettings.java里初始化WifiTracker。

@OverrIDepublic voID onActivityCreated(Bundle savedInstanceState) {    super.onActivityCreated(savedInstanceState);     mWifiTracker = WifiTrackerFactory.create(            getActivity(), this, getlifecycle(), true, true);    mWifiManager = mWifiTracker.getManager();    ...}

   

1.2 packages/apps/Settings/src/com/androID/settings/wifi/WifIEnabler.java

       应用层在扫描过程中貌似没做什么事情但暂且提一下WifIEnabler也会接收到WifiManager.WIFI_STATE_CHANGED_ACTION广播并会相关的处理。

private boolean mStateMachineEvent;private final IntentFilter mIntentFilter;private final broadcastReceiver mReceiver = new broadcastReceiver() {    @OverrIDe    public voID onReceive(Context context, Intent intent) {        String action = intent.getAction();        if (WifiManager.WIFI_STATE_CHANGED_ACTION.equals(action)) {            handleWifiStateChanged(mWifiManager.getWifiState());        } else if (WifiManager.SUPPliCANT_STATE_CHANGED_ACTION.equals(action)) {            if (!mConnected.get()) {                handleStateChanged(WifiInfo.getDetailedStateOf((SupplicantState)                        intent.getParcelableExtra(WifiManager.EXTRA_NEW_STATE)));            }        } else if (WifiManager.NETWORK_STATE_CHANGED_ACTION.equals(action)) {            NetworkInfo info = (NetworkInfo) intent.getParcelableExtra(                    WifiManager.EXTRA_NETWORK_INFO);            mConnected.set(info.isConnected());            handleStateChanged(info.getDetailedState());        }    }};

看handleWifiStateChanged。

private voID handleWifiStateChanged(int state) {    // Clear any prevIoUs state    mSwitchWidget.setDisabledByadmin(null);     switch (state) {        case WifiManager.WIFI_STATE_ENABliNG:            break;        case WifiManager.WIFI_STATE_ENABLED:            setSwitchbarChecked(true);            mSwitchWidget.setEnabled(true);            break;        case WifiManager.WIFI_STATE_disABliNG:            break;        case WifiManager.WIFI_STATE_Disabled:            setSwitchbarChecked(false);            mSwitchWidget.setEnabled(true);            break;        default:            setSwitchbarChecked(false);            mSwitchWidget.setEnabled(true);    }     if (RestrictedLockUtils.hasBaseUserRestriction(mContext,            UserManager.disALLOW_CONfig_TETHERING, UserHandle.myUserID())) {        mSwitchWidget.setEnabled(false);    } else {        final Enforcedadmin admin = RestrictedLockUtils.checkIfRestrictionEnforced(mContext,            UserManager.disALLOW_CONfig_TETHERING, UserHandle.myUserID());        mSwitchWidget.setDisabledByadmin(admin);    }}

根据wifi状态,switchbar的状态会变化。

 2 java框架层

     真正的扫描过程从这里开始。framework/base/packages/Settingslib。Settingslib放在frameworks/base/packages/Settingslib,因为systemUI和开机向导中的蓝牙WiFi流程也会用到对应的代码。

2.1 frameworks/base/packages/Settingslib/src/com/androID/settingslib/wifi/WifiTracker.java

/***  Receiver for handling broadcasts.**  This receiver is registered on the WorkHandler.*/@VisibleForTestingfinal broadcastReceiver mReceiver = new broadcastReceiver() {    @OverrIDe    public voID onReceive(Context context, Intent intent) {        String action = intent.getAction();         if (WifiManager.WIFI_STATE_CHANGED_ACTION.equals(action)) {            updateWifiState(intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,                            WifiManager.WIFI_STATE_UNKNowN));        } else if (WifiManager.SCAN_RESulTS_AVAILABLE_ACTION.equals(action)) {            mStaleScanResults = false;             fetchScansAndConfigsAndUpdateAccesspoints();        } else if (WifiManager.CONfigURED_NETWORKS_CHANGED_ACTION.equals(action)                || WifiManager.link_CONfigURATION_CHANGED_ACTION.equals(action)) {            fetchScansAndConfigsAndUpdateAccesspoints();        } else if (WifiManager.NETWORK_STATE_CHANGED_ACTION.equals(action)) {            // Todo(sghuman): Refactor these methods so they cannot result in duplicate            // onAccesspointsChanged updates being called from this intent.            NetworkInfo info = intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);            updateNetworkInfo(info);            fetchScansAndConfigsAndUpdateAccesspoints();        } else if (WifiManager.RSSI_CHANGED_ACTION.equals(action)) {            NetworkInfo info =                    mConnectivityManager.getNetworkInfo(mWifiManager.getCurrentNetwork());            updateNetworkInfo(info);        }    }};

看updateWifiState。

/*** Handles updates to WifiState.** <p>If Wifi is not enabled in the enabled state, {@link #mStaleScanResults} will be set to* true.*/private voID updateWifiState(int state) {    if (state == WifiManager.WIFI_STATE_ENABLED) {        if (mScanner != null) {            // We only need to resume if mScanner isn't null because            // that means we want to be scanning.            mScanner.resume();        }    } else {        clearaccesspointsAndConditionallyUpdate();        mLastInfo = null;        mLastNetworkInfo = null;        if (mScanner != null) {            mScanner.pause();        }        mStaleScanResults = true;    }    mListener.onWifiStateChanged(state);}

看mScanner.resume,其中Scanner是内部类。

@VisibleForTestingclass Scanner extends Handler {    static final int MSG_SCAN = 0;     private int mRetry = 0;     voID resume() {        if (!hasMessages(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);    }}

       在resume方法里面发送消息MSG_SCAN,并接收该消息进行处理,看handleMessage。会调用mWifiManager.startScan,并且每隔10s再次进行扫描。

 

2.2 frameworks/base/wifi/java/androID/net/wifi/WifiManager.java

* <p>* To initiate a Wi-Fi scan, declare the* {@link androID.Manifest.permission#CHANGE_WIFI_STATE}* permission in the manifest, and perform these steps:* </p>* <ol >* <li>Invoke the following method:* {@code ((WifiManager) getSystemService(WIFI_SERVICE)).startScan()}</li>* <li>* Register a broadcastReceiver to Listen to* {@code SCAN_RESulTS_AVAILABLE_ACTION}.</li>* <li>When a broadcast is received, call:* {@code ((WifiManager) getSystemService(WIFI_SERVICE)).getScanResults()}</li>* </ol>* @return {@code true} if the operation succeeded, i.e., the scan was initiated.* @deprecated The ability for apps to trigger scan requests will be removed in a future* release.*/@Deprecatedpublic boolean startScan() {    return startScan(null);} /** @hIDe */@SystemAPI@RequiresPermission(androID.Manifest.permission.UPDATE_DEVICE_STATS)public boolean startScan(WorkSource workSource) {    try {        String packagename = mContext.getopPackagename();        return mService.startScan(packagename);    } catch (remoteexception e) {        throw e.rethrowFromSystemServer();    }}

看mService.startScan。这个mService是远程的服务端WifiService,其实现类为WifiServiceImpl,这个过程也是跨进程调用。

 

2.3  frameworks/opt/net/wifi/service/java/com/androID/server/wifi/wifiServiceImpl.java

/*** See {@link androID.net.wifi.WifiManager#startScan}** @param packagename Package name of the app that requests wifi scan.*/@OverrIDepublic boolean startScan(String packagename) {    if (enforceChangePermission(packagename) != MODE_ALLOWED) {        return false;    }     int callingUID = Binder.getCallingUID();    long IDent = Binder.clearCallingIDentity();    mLog.info("startScan uID=%").c(callingUID).flush();    synchronized (this) {        if (mInIDleMode) {            // Need to send an immediate scan result broadcast in case the            // caller is waiting for a result ..             // Todo: investigate if the logic to cancel scans when IDle can move to            // WifiScanningServiceImpl.  This will 1 - clean up WifiServiceImpl and 2 -            // avoID plumbing an awkward path to report a cancelled/Failed scan.  This will            // be sent directly until b/31398592 is fixed.            sendFailedScanbroadcast();            mScanPending = true;            return false;        }    }    try {        mWifiPermissionsUtil.enforceCanAccessScanResults(packagename, callingUID);        Mutable<Boolean> scanSuccess = new Mutable<>();        boolean runWithScissoRSSuccess = mWifiInjector.getWifiStateMachineHandler()                .runWithScissors(() -> {                    scanSuccess.value = mScanRequestProxy.startScan(callingUID, packagename);                }, RUN_WITH_SCISSORS_TIMEOUT_MILliS);        if (!runWithScissoRSSuccess) {            Log.e(TAG, "Failed to post runnable to start scan");            sendFailedScanbroadcast();            return false;        }        if (!scanSuccess.value) {            Log.e(TAG, "Failed to start scan");            return false;        }    } catch (SecurityException e) {        return false;    } finally {        Binder.restoreCallingIDentity(IDent);    }    return true;}

继续看mScanRequestProxy.startScan。

 

2.4  frameworks/opt/net/wifi/service/java/com/androID/server/wifi/ScanRequestProxy.java

/*** Initiate a wifi scan.** @param callingUID The uID initiating the wifi scan. blame will be given to this uID.* @return true if the scan request was placed or a scan is already ongoing, false otherwise.*/public boolean startScan(int callingUID, String packagename) {    if (!retrIEveWifiScannerIfNecessary()) {        Log.e(TAG, "Failed to retrIEve wifiscanner");        sendScanResultFailurebroadcasttopackage(packagename);        return false;    }    boolean fromSettingsOrSetupWizard =            mWifiPermissionsUtil.checkNetworkSettingsPermission(callingUID)                    || mWifiPermissionsUtil.checkNetworkSetupWizardPermission(callingUID);    // Check and throttle scan request from apps without NETWORK_SETTINGS permission.    if (!fromSettingsOrSetupWizard            && shouldScanRequestBeThrottledForApp(callingUID, packagename)) {        Log.i(TAG, "Scan request from " + packagename + " throttled");        sendScanResultFailurebroadcasttopackage(packagename);        return false;    }    // Create a worksource using the caller's UID.    WorkSource workSource = new WorkSource(callingUID);     // Create the scan settings.    WifiScanner.ScanSettings settings = new WifiScanner.ScanSettings();    // Scan requests from apps with network settings will be of high accuracy type.    if (fromSettingsOrSetupWizard) {        settings.type = WifiScanner.TYPE_HIGH_ACCURACY;    }    // always do full scans    settings.band = WifiScanner.WIFI_BAND_BOTH_WITH_DFS;    settings.reportEvents = WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN            | WifiScanner.REPORT_EVENT_FulL_SCAN_RESulT;    if (mScanningForHIDdenNetworksEnabled) {        // retrIEve the List of hIDden network SSIDs to scan for, if enabled.        List<WifiScanner.ScanSettings.HIDdenNetwork> hIDdenNetworkList =                mWifiConfigManager.retrIEveHIDdenNetworkList();        settings.hIDdenNetworks = hIDdenNetworkList.toArray(                new WifiScanner.ScanSettings.HIDdenNetwork[hIDdenNetworkList.size()]);    }    mWifiScanner.startScan(settings, new ScanRequestProxyScanListener(), workSource);    mIsScanProcessingComplete = false;    return true;}

看mWifiScanner.startScan

 

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

        AndroID P和AndroID O框架层代码改变不是很大,不过AndroID O的 *** 作基本都是经过WifiStateMachine状态机,而AndroID P很多 *** 作都不再经过WifiStateMachine状态机,在这里是为了把scan功能独立分开出来。而和AndroID O之前的代码相比则有很大区别,这里接下来使用到了双向异步通道的方式,mAsyncChannel.sendMessage。AsyncChannel处理两个handler之间消息异步传递的问题,这两个handler可以在一个进程也可以处于不同的进程。 

 

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

private class ClIEntHandler extends WifiHandler {     ClIEntHandler(String tag, Looper looper) {        super(tag, looper);    }     @OverrIDe    public voID handleMessage(Message msg) {        super.handleMessage(msg);        ...        switch (msg.what) {            case WifiScanner.CMD_START_BACKGROUND_SCAN:            case WifiScanner.CMD_Stop_BACKGROUND_SCAN:                mBackgroundScanStateMachine.sendMessage(Message.obtain(msg));                break;            case WifiScanner.CMD_START_PNO_SCAN:            case WifiScanner.CMD_Stop_PNO_SCAN:                mPnoScanStateMachine.sendMessage(Message.obtain(msg));                break;            case WifiScanner.CMD_START_SINGLE_SCAN:            case WifiScanner.CMD_Stop_SINGLE_SCAN:                mSingleScanStateMachine.sendMessage(Message.obtain(msg));                break;            ...        }    }}

   ClIEntHandler接收到CMD_START_SINGLE_SCAN消息并处理也就是向状态机发送这个消息,mSingleScanStateMachine.sendMessage(Message.obtain(msg))。SingleScanStateMachine是个处理热点扫描的状态机。

/*** State machine that holds the state of single scans. Scans should only be active in the* ScanningState. The pending scans and active scans maps are swapped when entering* ScanningState. Any requests queued while scanning will be placed in the pending queue and* executed after Transitioning back to IDleState.*/class WifiSingleScanStateMachine extends StateMachine implements WifiNative.ScanEventHandler {    /**    * Maximum age of results that we return from our cache via    * {@link WifiScanner#getScanResults()}.    * This is currently set to 3 minutes to restore parity with the wpa_supplicant's scan    * result cache expiration policy. (See b/62253332 for details)    */    @VisibleForTesting    public static final int CACHED_SCAN_RESulTS_MAX_AGE_IN_MILliS = 180 * 1000;     private final DefaultState mDefaultState = new DefaultState();    private final DriverStartedState mDriverStartedState = new DriverStartedState();    private final IDleState  mIDleState  = new IDleState();    private final ScanningState  mScanningState  = new ScanningState();     private WifiNative.ScanSettings mActiveScanSettings = null;    private RequestList<ScanSettings> mActiveScans = new RequestList<>();    private RequestList<ScanSettings> mPendingScans = new RequestList<>();     // Scan results cached from the last full single scan request.    private final List<ScanResult> mCachedScanResults = new ArrayList<>();     WifiSingleScanStateMachine(Looper looper) {        super("WifiSingleScanStateMachine", looper);         setLogRecSize(128);        setlogonlyTransitions(false);         // CHECKSTYLE:OFF IndentationCheck        addState(mDefaultState);            addState(mDriverStartedState, mDefaultState);                addState(mIDleState, mDriverStartedState);                addState(mScanningState, mDriverStartedState);            // CHECKSTYLE:ON IndentationCheck             setinitialState(mDefaultState);    }    ...}

状态机有四个状态,初始状态为默认状态。在DriverStarted对CMD_START_SINGLE_SCAN消息进行处理。

/*** State representing when the driver is running. This state is not meant to be Transitioned* directly, but is instead intended 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 boolean processMessage(Message msg) {        ClIEntInfo ci = mClIEnts.get(msg.replyTo);         switch (msg.what) {            case CMD_DRIVER_LOADED:                // Ignore if we're already in driver loaded state.                return HANDLED;            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)) {                            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 {                ...                }            }    }   }

看调用的tryToStartNewScan。

voID tryToStartNewScan() {    if (mPendingScans.size() == 0) { // no pending requests        return;    }    ...    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。

 

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

/*** Start a one time scan. This method should only be called when there is no scan going on* (after a callback indicating that the prevIoUs scan succeeded/Failed).* @return if the scan paramaters are valID* Note this may return true even if the parameters are not accepted by the chip because the* scan may be scheduled async.*/public abstract boolean startSingleScan(WifiNative.ScanSettings settings,                 WifiNative.ScanEventHandler eventHandler);

 

2.8  frameworks/opt/net/wifi/service/java/com/androID/server/wifi/scanner/WificondScannerImpl.java

WificondScannerImpl.java继承抽象类WifiScannerImpl.java,所以复写了startSingleScan。

@OverrIDepublic boolean startSingleScan(WifiNative.ScanSettings settings,        WifiNative.ScanEventHandler eventHandler) {    ...    if (!allFreqs.isEmpty()) {        freqs = allFreqs.getScanFreqs();        success = mWifiNative.scan(                        mIfacename, settings.scanType, 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");    }    if (success) {        if (DBG) {            Log.d(TAG, "Starting wifi scan for freqs=" + freqs);        }         mScanTimeoutListener = new AlarmManager.OnAlarmListener() {            @OverrIDe public voID onAlarm() {                handleScanTimeout();            }        };         mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,                    mClock.getElapsedSinceBootMillis() + SCAN_TIMEOUT_MS,                        TIMEOUT_ALARM_TAG, mScanTimeoutListener, mEventHandler);        } else {            // indicate scan failure async            mEventHandler.post(new Runnable() {                @OverrIDe public voID run() {                    reportScanFailure();                }            });        }         return true;    }}

看 mWifiNative.scan,java框架层最终还是会调用到native层。

 

2.9  frameworks/opt/net/wifi/service/java/com/androID/server/wifi/WifiNative.java

/*** Start a scan using wificond for the given parameters.* @param ifacename name of the interface.* @param scanType Type of scan to perform. One of {@link ScanSettings#SCAN_TYPE_LOW_LATENCY},* {@link ScanSettings#SCAN_TYPE_LOW_POWER} or {@link ScanSettings#SCAN_TYPE_HIGH_ACCURACY}.* @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(@NonNull String ifacename, int scanType, Set<Integer> freqs,            Set<String> hIDdenNetworkSSIDs) {    return mWificondControl.scan(ifacename, scanType, freqs, hIDdenNetworkSSIDs);}

看mWificondControl.scan。

 

2.10  frameworks/opt/net/wifi/service/java/com/androID/server/wifi/WificondControl.java

/*** Start a scan using wificond for the given parameters.* @param ifacename name of the interface.* @param scanType Type of scan to perform.* @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(@NonNull String ifacename,                    int scanType,                    Set<Integer> freqs,                    Set<String> hIDdenNetworkSSIDs) {    IWifiScannerImpl scannerImpl = getScannerImpl(ifacename);    if (scannerImpl == null) {        Log.e(TAG, "No valID wificond scanner interface handler");        return false;    }    SingleScanSettings settings = new SingleScanSettings();    try {        settings.scanType = getScanType(scanType);    } catch (IllegalArgumentException e) {        Log.e(TAG, "InvalID scan type ", e);        return false;    }    settings.channelSettings  = new ArrayList<>();    settings.hIDdenNetworks  = new ArrayList<>();     if (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 scannerImpl.scan(settings);    } catch (remoteexception e1) {        Log.e(TAG, "Failed to request scan due to remote exception");    }    return false;}

又调到scannerImpl.scan了,看getScannerImpl。

/** Helper function to look up the scanner impl handle using name */private IWifiScannerImpl getScannerImpl(@NonNull String ifacename) {    return mWificondScanners.get(ifacename);}

看mWificondScanners怎么来的,从下面可以看到wificondScanner = clIEntInterface.getWifiScannerImpl()。

/*** Setup interface for clIEnt mode via wificond.* @return An IClIEntInterface as wificond clIEnt interface binder handler.* Returns null on failure.*/public IClIEntInterface setupInterfaceForClIEntMode(@NonNull String ifacename) {    Log.d(TAG, "Setting up interface for clIEnt mode");    if (!retrIEveWificondAndRegisterForDeath()) {        return null;    }     IClIEntInterface clIEntInterface = null;    try {        clIEntInterface = mWificond.createClIEntInterface(ifacename);    } 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    mClIEntInterfaces.put(ifacename, clIEntInterface);    try {        IWifiScannerImpl wificondScanner = clIEntInterface.getWifiScannerImpl();        if (wificondScanner == null) {            Log.e(TAG, "Failed to get WificondScannerImpl");            return null;        }        mWificondScanners.put(ifacename, wificondScanner);        Binder.allowBlocking(wificondScanner.asBinder());        ScanEventHandler scanEventHandler = new ScanEventHandler(ifacename);        mScanEventHandlers.put(ifacename,  scanEventHandler);        wificondScanner.subscribeScanEvents(scanEventHandler);        PnoScanEventHandler pnoScanEventHandler = new PnoScanEventHandler(ifacename);        mPnoScanEventHandlers.put(ifacename,  pnoScanEventHandler);        wificondScanner.subscribePnoScanEvents(pnoScanEventHandler);    } catch (remoteexception e) {        Log.e(TAG, "Failed to refresh wificond scanner due to remote exception");    }     return clIEntInterface;}

看retrIEveWificondAndRegisterForDeath。

/*** Helper method to retrIEve the global wificond handle and register for* death notifications.*/private boolean retrIEveWificondAndRegisterForDeath() {    if (mWificond != null) {        if (mVerboseLoggingEnabled) {            Log.d(TAG, "Wificond handle already retrIEved");        }        // We already have a wificond handle.        return true;    }    mWificond = mWifiInjector.makeWificond();    if (mWificond == null) {        Log.e(TAG, "Failed to get reference to wificond");        return false;    }    try {        mWificond.asBinder().linkToDeath(this, 0);    } catch (remoteexception e) {        Log.e(TAG, "Failed to register death notification for wificond");        // The remote has already dIEd.        return false;    }    return true;}

看mWiifInjector.makeWificond。

 

2.11  frameworks/opt/net/wifi/service/java/com/androID/server/wifi/WifiInjector.java

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

再往下走就是C++层了。往下的部分以后有机会再继续深入。

 

四 总结

 wifi框架层从AndroID O版本开始变化还是挺大的,AndroID P是延续AndroID O 的改变做了一些不怎么大的变化:

      (1) 与其他AndroID版本相比,整体架构还好,多了wificond跟底层通信,framework整个修改比较大;

     (2) AndroID O  scan、scan_results命令不再通过wpa_supplicant下发到kernel,而是直接由wificond传送到kernel,而scan results的结果也是直接由kernel传给wificond,再由wificond传送给上层去显示;

      (3) wifi direct的p2p find还是通过wpa-supplicant通信 ;

      (4) wifi的连接等 *** 作,还是通过wpa_supplicant进行。

总结

以上是内存溢出为你收集整理的[转载] Wifi模块—源码分析Wifi热点扫描(Android P)全部内容,希望文章能够帮你解决[转载] Wifi模块—源码分析Wifi热点扫描(Android P)所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/web/1102998.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2022-05-28
下一篇2022-05-28

发表评论

登录后才能评论

评论列表(0条)

    保存