![[转载] Wifi模块—源码分析Wifi热点扫描(Android P),第1张 [转载] Wifi模块—源码分析Wifi热点扫描(Android P),第1张](/aiimages/%5B%E8%BD%AC%E8%BD%BD%5D+Wifi%E6%A8%A1%E5%9D%97%E2%80%94%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90Wifi%E7%83%AD%E7%82%B9%E6%89%AB%E6%8F%8F%EF%BC%88Android+P%EF%BC%89.png)
这次接着讲Wifi工程流程中的Wifi热点查找过程,也是Wifi启动的过程延续,Wifi启动过程中会更新Wifi的状态,框架层也有相应广播发出,应用层接收到广播后开始进行热点的扫描。可以先看前面Wifi启动的分析过程。
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)所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)