这次接着讲Wifi工程流程中的Wifi热点扫描过程部分的获取扫描结果的过程,也是Wifi扫描过程的延续,可以先看前面Wifi扫描的分析过程。
Wifi模块—源码分析Wifi热点扫描(Android P)
二 图示调用流程
这次的调用流程比较简单就不画流程图了,而且流程是按三条不连贯的线路分析的。
三 代码具体流程
1 底层获取扫描结果
在上一篇我们分析了Wifi扫描的过程。在底层完成扫描之后会通知框架层,由框架层的WifiMonitor监听该事件并发送消息SCAN_RESULTS_EVENT,通知WificondScannerImpl进行处理,再通过WifiNative从底层获取wifi扫描结果,最后再广播SCAN_RESULTS_AVAILABLE_ACTION通知扫描结果可获取。
1.1 framework/opt/net/wifi/service/java/com/android/server/wifi/WifiMonitor.java
- /**
- * Broadcast scan result event to all the handlers registered for this event.
- * @param iface Name of iface on which this occurred.
- */
- public void broadcastScanResultEvent(String iface) {
- sendMessage(iface, SCAN_RESULTS_EVENT);
- }
1.2 framework/opt/net/wifi/service/java/com/android/server/wifi/scanner/WificondScannerImpl.java
- @Override
- public boolean handleMessage(Message msg) {
- switch(msg.what) {
- case WifiMonitor.SCAN_FAILED_EVENT:
- Log.w(TAG, "Scan failed");
- cancelScanTimeout();
- reportScanFailure();
- break;
- case WifiMonitor.PNO_SCAN_RESULTS_EVENT:
- pollLatestScanDataForPno();
- break;
- case WifiMonitor.SCAN_RESULTS_EVENT:
- cancelScanTimeout();
- pollLatestScanData();
- break;
- default:
- // ignore unknown event
- }
- return true;
- }
继续看 pollLatestScanData。
- private void pollLatestScanData() {
- synchronized (mSettingsLock) {
- if (mLastScanSettings == null) {
- // got a scan before we started scanning or after scan was canceled
- return;
- }
-
- mNativeScanResults = mWifiNative.getScanResults(mIfaceName);
- List<ScanResult> singleScanResults = new ArrayList<>();
- int numFilteredScanResults = 0;
- for (int i = 0; i < mNativeScanResults.size(); ++i) {
- ScanResult result = mNativeScanResults.get(i).getScanResult();
- long timestamp_ms = result.timestamp / 1000; // convert us -> ms
- if (timestamp_ms > mLastScanSettings.startTime) {
- if (mLastScanSettings.singleScanFreqs.containsChannel(
- result.frequency)) {
- singleScanResults.add(result);
- }
- } else {
- numFilteredScanResults++;
- }
- }
- ...
- }
- }
通过mWifiNative.getScanResults来从底层获取wifi热点扫描结果。
1.3 framework/opt/net/wifi/service/java/com/android/server/wifi/WifiNative.java
- /**
- * Fetch the latest scan result from kernel via wificond.
- * @param ifaceName Name of the interface.
- * @return Returns an ArrayList of ScanDetail.
- * Returns an empty ArrayList on failure.
- */
- public ArrayList<ScanDetail> getScanResults(@NonNull String ifaceName) {
- return mWificondControl.getScanResults(
- ifaceName, WificondControl.SCAN_TYPE_SINGLE_SCAN);
- }
接着看mWificondControl.getScanResults。
1.4 framework/opt/net/wifi/service/java/com/android/server/wifi/WifiNative.java
- /**
- * Fetch the latest scan result from kernel via wificond.
- * @param ifaceName Name of the interface.
- * @return Returns an ArrayList of ScanDetail.
- * Returns an empty ArrayList on failure.
- */
- public ArrayList<ScanDetail> getScanResults(@NonNull String ifaceName, int scanType) {
- ArrayList<ScanDetail> results = new ArrayList<>();
- IWifiScannerImpl scannerImpl = getScannerImpl(ifaceName);
- if (scannerImpl == null) {
- Log.e(TAG, "No valid wificond scanner interface handler");
- return results;
- }
- try {
- NativeScanResult[] nativeResults;
- if (scanType == SCAN_TYPE_SINGLE_SCAN) {
- nativeResults = scannerImpl.getScanResults();
- } else {
- nativeResults = scannerImpl.getPnoScanResults();
- }
- ...
- }
- ...
-
- return results;
- }
看scannerImpl.getScanResults。
1.5 system/connectivity/wificond/aidl/android/net/wifi/IWifiScannerImpl.aidl
接下来就会调到C++层,暂时就不往下分析了。
2 通知扫描结果可获取
接下来广播SCAN_RESULTS_AVAILABLE_ACTION通知扫描结果可获取。
2.1 frameworks/base/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
在这里会接收到扫描结果可获取的广播WifiManager.SCAN_RESULTS_AVAILABLE_ACTION。
- /**
- * Receiver for handling broadcasts.
- *
- * This receiver is registered on the WorkHandler.
- */
- @VisibleForTesting
- 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)) {
- 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);
- }
- }
- };
WifiTracker接收到这个广播后,执行fetchScansAndConfigsAndUpdateAccessPoints。
- /**
- * Retrieves latest scan results and wifi configs, then calls
- * {@link #updateAccessPoints(List, List)}.
- */
- private void fetchScansAndConfigsAndUpdateAccessPoints() {
- final List<ScanResult> newScanResults = mWifiManager.getScanResults();
- if (isVerboseLoggingEnabled()) {
- Log.i(TAG, "Fetched scan results: " + newScanResults);
- }
-
- List<WifiConfiguration> configs = mWifiManager.getConfiguredNetworks();
- updateAccessPoints(newScanResults, configs);
- }
走到mWifiManager.getScanResults。
2.2 framework/base/wifi/java/android/net/wifi/WifiManager.java
- /**
- * Return the results of the latest access point scan.
- * @return the list of access points found in the most recent scan. An app must hold
- * {@link android.Manifest.permission#ACCESS_COARSE_LOCATION ACCESS_COARSE_LOCATION} or
- * {@link android.Manifest.permission#ACCESS_FINE_LOCATION ACCESS_FINE_LOCATION} permission
- * in order to get valid results. If there is a remote exception (e.g., either a communication
- * problem with the system service or an exception within the framework) an empty list will be
- * returned.
- */
- public List<ScanResult> getScanResults() {
- try {
- return mService.getScanResults(mContext.getOpPackageName());
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
又是通过aidl进行跨进程调用mService.getScanResults。
2.3 framework/opt/net/wifi/service/java/com/android/server/wifi/WifiServiceImpl.java
- /**
- * Return the results of the most recent access point scan, in the form of
- * a list of {@link ScanResult} objects.
- * @return the list of results
- */
- @Override
- public List<ScanResult> getScanResults(String callingPackage) {
- enforceAccessPermission();
- int uid = Binder.getCallingUid();
- long ident = Binder.clearCallingIdentity();
- if (mVerboseLoggingEnabled) {
- mLog.info("getScanResults uid=%").c(uid).flush();
- }
- try {
- mWifiPermissionsUtil.enforceCanAccessScanResults(callingPackage, uid);
- final List<ScanResult> scanResults = new ArrayList<>();
- boolean success = mWifiInjector.getWifiStateMachineHandler().runWithScissors(() -> {
- scanResults.addAll(mScanRequestProxy.getScanResults());
- }, RUN_WITH_SCISSORS_TIMEOUT_MILLIS);
- if (!success) {
- Log.e(TAG, "Failed to post runnable to fetch scan results");
- }
- return scanResults;
- } catch (SecurityException e) {
- return new ArrayList<ScanResult>();
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- }
返回scanResults。
这里和android O还是有一些差别的。看mScanRequestProxy.getScanResults。
2.4 framework/opt/net/wifi/service/java/com/android/server/wifi/ScanRequestProxy.java
- /**
- * Return the results of the most recent access point scan, in the form of
- * a list of {@link ScanResult} objects.
- * @return the list of results
- */
- public List<ScanResult> getScanResults() {
- return mLastScanResults;
- }
看看mLastScanResults怎么来的。
- // Common scan listener for scan requests.
- private class ScanRequestProxyScanListener implements WifiScanner.ScanListener {
- ...
- @Override
- public void onResults(WifiScanner.ScanData[] scanDatas) {
- if (mVerboseLoggingEnabled) {
- Log.d(TAG, "Scan results received");
- }
- // For single scans, the array size should always be 1.
- if (scanDatas.length != 1) {
- Log.wtf(TAG, "Found more than 1 batch of scan results, Failing...");
- sendScanResultBroadcastIfScanProcessingNotComplete(false);
- return;
- }
- WifiScanner.ScanData scanData = scanDatas[0];
- ScanResult[] scanResults = scanData.getResults();
- if (mVerboseLoggingEnabled) {
- Log.d(TAG, "Received " + scanResults.length + " scan results");
- }
- // Store the last scan results & send out the scan completion broadcast.
- mLastScanResults.clear();
- mLastScanResults.addAll(Arrays.asList(scanResults));
- sendScanResultBroadcastIfScanProcessingNotComplete(true);
- }
- ...
- };
将scanResults放进LastScanResults,看scanData.getResults。WifiScanner的服务端是WifiScanningServiceImpl。
2.5 framework/base/wifi/java/android/net/wifi//WifiScanner.java
- /**
- * all the information garnered from a single scan
- */
- public static class ScanData implements Parcelable {
-
- ...
- public ScanResult[] getResults() {
- return mResults;
- }
- ...
- }
返回mResults。
3 Settings应用层获取扫描结果
应用层
3.1 packages/apps/Settings/src/com/android/settings/wifi/WifiSettings.java
在生命周期函数里监听Wifi的状态。
- @Override
- public void onStart() {
- super.onStart();
-
- // On/off switch is hidden for Setup Wizard (returns null)
- mWifiEnabler = createWifiEnabler();
-
- if (mIsRestricted) {
- restrictUi();
- return;
- }
-
- onWifiStateChanged(mWifiManager.getWifiState());
- }
当wifi状态改变时会有相应的操作。
- /** Called when the state of Wifi has changed. */
- @Override
- public void onWifiStateChanged(int state) {
- if (mIsRestricted) {
- return;
- }
-
- final int wifiState = mWifiManager.getWifiState();
- switch (wifiState) {
- case WifiManager.WIFI_STATE_ENABLED:
- updateAccessPointPreferences();
- break;
-
- case WifiManager.WIFI_STATE_ENABLING:
- removeConnectedAccessPointPreference();
- mAccessPointsPreferenceCategory.removeAll();
- addMessagePreference(R.string.wifi_starting);
- setProgressBarVisible(true);
- break;
-
- case WifiManager.WIFI_STATE_DISABLING:
- removeConnectedAccessPointPreference();
- mAccessPointsPreferenceCategory.removeAll();
- addMessagePreference(R.string.wifi_stopping);
- break;
-
- case WifiManager.WIFI_STATE_DISABLED:
- setOffMessage();
- setAdditionalSettingsSummaries();
- setProgressBarVisible(false);
- break;
- }
- }
监听到wifi状态已经开启,看updateAccessPointPreferences。
- private void updateAccessPointPreferences() {
- // in case state has changed
- if (!mWifiManager.isWifiEnabled()) {
- return;
- }
- // AccessPoints are sorted by the WifiTracker
- final List<AccessPoint> accessPoints = mWifiTracker.getAccessPoints();
- if (isVerboseLoggingEnabled()) {
- Log.i(TAG, "updateAccessPoints called for: " + accessPoints);
- }
- ...
- }
看mWifiTracker.getAccessPoints。
java框架层
3.2 frameworks/base/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
- /**
- * Gets the current list of access points.
- *
- * <p>This method is can be called on an abitrary thread by clients, but is normally called on
- * the UI Thread by the rendering App.
- */
- @AnyThread
- public List<AccessPoint> getAccessPoints() {
- synchronized (mLock) {
- return new ArrayList<>(mInternalAccessPoints);
- }
- }
接下来的过程最终还是会走到WifiManager.getScanResults,WifiServiceImpl.getScanResults,细节上会有差异。
来源:https://blog.csdn.net/m0_37905055/article/details/101263698