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

孤街醉人 提交于 2019-11-30 09:31:51
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_42093428/article/details/82834234

一 前言

       这次接着讲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

  1. /**
  2. * Broadcast scan result event to all the handlers registered for this event.
  3. * @param iface Name of iface on which this occurred.
  4. */
  5. public void broadcastScanResultEvent(String iface) {
  6. sendMessage(iface, SCAN_RESULTS_EVENT);
  7. }

 

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

  1. @Override
  2. public boolean handleMessage(Message msg) {
  3. switch(msg.what) {
  4. case WifiMonitor.SCAN_FAILED_EVENT:
  5. Log.w(TAG, "Scan failed");
  6. cancelScanTimeout();
  7. reportScanFailure();
  8. break;
  9. case WifiMonitor.PNO_SCAN_RESULTS_EVENT:
  10. pollLatestScanDataForPno();
  11. break;
  12. case WifiMonitor.SCAN_RESULTS_EVENT:
  13. cancelScanTimeout();
  14. pollLatestScanData();
  15. break;
  16. default:
  17. // ignore unknown event
  18. }
  19. return true;
  20. }

继续看 pollLatestScanData。

  1. private void pollLatestScanData() {
  2. synchronized (mSettingsLock) {
  3. if (mLastScanSettings == null) {
  4. // got a scan before we started scanning or after scan was canceled
  5. return;
  6. }
  7. mNativeScanResults = mWifiNative.getScanResults(mIfaceName);
  8. List<ScanResult> singleScanResults = new ArrayList<>();
  9. int numFilteredScanResults = 0;
  10. for (int i = 0; i < mNativeScanResults.size(); ++i) {
  11. ScanResult result = mNativeScanResults.get(i).getScanResult();
  12. long timestamp_ms = result.timestamp / 1000; // convert us -> ms
  13. if (timestamp_ms > mLastScanSettings.startTime) {
  14. if (mLastScanSettings.singleScanFreqs.containsChannel(
  15. result.frequency)) {
  16. singleScanResults.add(result);
  17. }
  18. } else {
  19. numFilteredScanResults++;
  20. }
  21. }
  22. ...
  23. }
  24. }

 通过mWifiNative.getScanResults来从底层获取wifi热点扫描结果。

 

1.3 framework/opt/net/wifi/service/java/com/android/server/wifi/WifiNative.java

  1. /**
  2. * Fetch the latest scan result from kernel via wificond.
  3. * @param ifaceName Name of the interface.
  4. * @return Returns an ArrayList of ScanDetail.
  5. * Returns an empty ArrayList on failure.
  6. */
  7. public ArrayList<ScanDetail> getScanResults(@NonNull String ifaceName) {
  8. return mWificondControl.getScanResults(
  9. ifaceName, WificondControl.SCAN_TYPE_SINGLE_SCAN);
  10. }

接着看mWificondControl.getScanResults。

 

1.4 framework/opt/net/wifi/service/java/com/android/server/wifi/WifiNative.java

  1. /**
  2. * Fetch the latest scan result from kernel via wificond.
  3. * @param ifaceName Name of the interface.
  4. * @return Returns an ArrayList of ScanDetail.
  5. * Returns an empty ArrayList on failure.
  6. */
  7. public ArrayList<ScanDetail> getScanResults(@NonNull String ifaceName, int scanType) {
  8. ArrayList<ScanDetail> results = new ArrayList<>();
  9. IWifiScannerImpl scannerImpl = getScannerImpl(ifaceName);
  10. if (scannerImpl == null) {
  11. Log.e(TAG, "No valid wificond scanner interface handler");
  12. return results;
  13. }
  14. try {
  15. NativeScanResult[] nativeResults;
  16. if (scanType == SCAN_TYPE_SINGLE_SCAN) {
  17. nativeResults = scannerImpl.getScanResults();
  18. } else {
  19. nativeResults = scannerImpl.getPnoScanResults();
  20. }
  21. ...
  22. }
  23. ...
  24. return results;
  25. }

看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。

  1. /**
  2. * Receiver for handling broadcasts.
  3. *
  4. * This receiver is registered on the WorkHandler.
  5. */
  6. @VisibleForTesting
  7. final BroadcastReceiver mReceiver = new BroadcastReceiver() {
  8. @Override
  9. public void onReceive(Context context, Intent intent) {
  10. String action = intent.getAction();
  11. if (WifiManager.WIFI_STATE_CHANGED_ACTION.equals(action)) {
  12. updateWifiState(
  13. intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
  14. WifiManager.WIFI_STATE_UNKNOWN));
  15. } else if (WifiManager.SCAN_RESULTS_AVAILABLE_ACTION.equals(action)) {
  16. mStaleScanResults = false;
  17. fetchScansAndConfigsAndUpdateAccessPoints();
  18. } else if (WifiManager.CONFIGURED_NETWORKS_CHANGED_ACTION.equals(action)
  19. || WifiManager.LINK_CONFIGURATION_CHANGED_ACTION.equals(action)) {
  20. fetchScansAndConfigsAndUpdateAccessPoints();
  21. } else if (WifiManager.NETWORK_STATE_CHANGED_ACTION.equals(action)) {
  22. // TODO(sghuman): Refactor these methods so they cannot result in duplicate
  23. // onAccessPointsChanged updates being called from this intent.
  24. NetworkInfo info = intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
  25. updateNetworkInfo(info);
  26. fetchScansAndConfigsAndUpdateAccessPoints();
  27. } else if (WifiManager.RSSI_CHANGED_ACTION.equals(action)) {
  28. NetworkInfo info =
  29. mConnectivityManager.getNetworkInfo(mWifiManager.getCurrentNetwork());
  30. updateNetworkInfo(info);
  31. }
  32. }
  33. };

WifiTracker接收到这个广播后,执行fetchScansAndConfigsAndUpdateAccessPoints。

  1. /**
  2. * Retrieves latest scan results and wifi configs, then calls
  3. * {@link #updateAccessPoints(List, List)}.
  4. */
  5. private void fetchScansAndConfigsAndUpdateAccessPoints() {
  6. final List<ScanResult> newScanResults = mWifiManager.getScanResults();
  7. if (isVerboseLoggingEnabled()) {
  8. Log.i(TAG, "Fetched scan results: " + newScanResults);
  9. }
  10. List<WifiConfiguration> configs = mWifiManager.getConfiguredNetworks();
  11. updateAccessPoints(newScanResults, configs);
  12. }

走到mWifiManager.getScanResults。

 

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

  1. /**
  2. * Return the results of the latest access point scan.
  3. * @return the list of access points found in the most recent scan. An app must hold
  4. * {@link android.Manifest.permission#ACCESS_COARSE_LOCATION ACCESS_COARSE_LOCATION} or
  5. * {@link android.Manifest.permission#ACCESS_FINE_LOCATION ACCESS_FINE_LOCATION} permission
  6. * in order to get valid results. If there is a remote exception (e.g., either a communication
  7. * problem with the system service or an exception within the framework) an empty list will be
  8. * returned.
  9. */
  10. public List<ScanResult> getScanResults() {
  11. try {
  12. return mService.getScanResults(mContext.getOpPackageName());
  13. } catch (RemoteException e) {
  14. throw e.rethrowFromSystemServer();
  15. }
  16. }

又是通过aidl进行跨进程调用mService.getScanResults。

 

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

  1. /**
  2. * Return the results of the most recent access point scan, in the form of
  3. * a list of {@link ScanResult} objects.
  4. * @return the list of results
  5. */
  6. @Override
  7. public List<ScanResult> getScanResults(String callingPackage) {
  8. enforceAccessPermission();
  9. int uid = Binder.getCallingUid();
  10. long ident = Binder.clearCallingIdentity();
  11. if (mVerboseLoggingEnabled) {
  12. mLog.info("getScanResults uid=%").c(uid).flush();
  13. }
  14. try {
  15. mWifiPermissionsUtil.enforceCanAccessScanResults(callingPackage, uid);
  16. final List<ScanResult> scanResults = new ArrayList<>();
  17. boolean success = mWifiInjector.getWifiStateMachineHandler().runWithScissors(() -> {
  18. scanResults.addAll(mScanRequestProxy.getScanResults());
  19. }, RUN_WITH_SCISSORS_TIMEOUT_MILLIS);
  20. if (!success) {
  21. Log.e(TAG, "Failed to post runnable to fetch scan results");
  22. }
  23. return scanResults;
  24. } catch (SecurityException e) {
  25. return new ArrayList<ScanResult>();
  26. } finally {
  27. Binder.restoreCallingIdentity(ident);
  28. }
  29. }

返回scanResults。

这里和android O还是有一些差别的。看mScanRequestProxy.getScanResults。

 

2.4 framework/opt/net/wifi/service/java/com/android/server/wifi/ScanRequestProxy.java

  1. /**
  2. * Return the results of the most recent access point scan, in the form of
  3. * a list of {@link ScanResult} objects.
  4. * @return the list of results
  5. */
  6. public List<ScanResult> getScanResults() {
  7. return mLastScanResults;
  8. }

看看mLastScanResults怎么来的。

  1. // Common scan listener for scan requests.
  2. private class ScanRequestProxyScanListener implements WifiScanner.ScanListener {
  3. ...
  4. @Override
  5. public void onResults(WifiScanner.ScanData[] scanDatas) {
  6. if (mVerboseLoggingEnabled) {
  7. Log.d(TAG, "Scan results received");
  8. }
  9. // For single scans, the array size should always be 1.
  10. if (scanDatas.length != 1) {
  11. Log.wtf(TAG, "Found more than 1 batch of scan results, Failing...");
  12. sendScanResultBroadcastIfScanProcessingNotComplete(false);
  13. return;
  14. }
  15. WifiScanner.ScanData scanData = scanDatas[0];
  16. ScanResult[] scanResults = scanData.getResults();
  17. if (mVerboseLoggingEnabled) {
  18. Log.d(TAG, "Received " + scanResults.length + " scan results");
  19. }
  20. // Store the last scan results & send out the scan completion broadcast.
  21. mLastScanResults.clear();
  22. mLastScanResults.addAll(Arrays.asList(scanResults));
  23. sendScanResultBroadcastIfScanProcessingNotComplete(true);
  24. }
  25. ...
  26. };

将scanResults放进LastScanResults,看scanData.getResults。WifiScanner的服务端是WifiScanningServiceImpl。

 

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

  1. /**
  2. * all the information garnered from a single scan
  3. */
  4. public static class ScanData implements Parcelable {
  5. ...
  6. public ScanResult[] getResults() {
  7. return mResults;
  8. }
  9. ...
  10. }

返回mResults。

 

3 Settings应用层获取扫描结果

应用层

3.1 packages/apps/Settings/src/com/android/settings/wifi/WifiSettings.java

在生命周期函数里监听Wifi的状态。

  1. @Override
  2. public void onStart() {
  3. super.onStart();
  4. // On/off switch is hidden for Setup Wizard (returns null)
  5. mWifiEnabler = createWifiEnabler();
  6. if (mIsRestricted) {
  7. restrictUi();
  8. return;
  9. }
  10. onWifiStateChanged(mWifiManager.getWifiState());
  11. }

当wifi状态改变时会有相应的操作。

  1. /** Called when the state of Wifi has changed. */
  2. @Override
  3. public void onWifiStateChanged(int state) {
  4. if (mIsRestricted) {
  5. return;
  6. }
  7. final int wifiState = mWifiManager.getWifiState();
  8. switch (wifiState) {
  9. case WifiManager.WIFI_STATE_ENABLED:
  10. updateAccessPointPreferences();
  11. break;
  12. case WifiManager.WIFI_STATE_ENABLING:
  13. removeConnectedAccessPointPreference();
  14. mAccessPointsPreferenceCategory.removeAll();
  15. addMessagePreference(R.string.wifi_starting);
  16. setProgressBarVisible(true);
  17. break;
  18. case WifiManager.WIFI_STATE_DISABLING:
  19. removeConnectedAccessPointPreference();
  20. mAccessPointsPreferenceCategory.removeAll();
  21. addMessagePreference(R.string.wifi_stopping);
  22. break;
  23. case WifiManager.WIFI_STATE_DISABLED:
  24. setOffMessage();
  25. setAdditionalSettingsSummaries();
  26. setProgressBarVisible(false);
  27. break;
  28. }
  29. }

监听到wifi状态已经开启,看updateAccessPointPreferences。

  1. private void updateAccessPointPreferences() {
  2. // in case state has changed
  3. if (!mWifiManager.isWifiEnabled()) {
  4. return;
  5. }
  6. // AccessPoints are sorted by the WifiTracker
  7. final List<AccessPoint> accessPoints = mWifiTracker.getAccessPoints();
  8. if (isVerboseLoggingEnabled()) {
  9. Log.i(TAG, "updateAccessPoints called for: " + accessPoints);
  10. }
  11. ...
  12. }

看mWifiTracker.getAccessPoints。

 

 java框架层

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

  1. /**
  2. * Gets the current list of access points.
  3. *
  4. * <p>This method is can be called on an abitrary thread by clients, but is normally called on
  5. * the UI Thread by the rendering App.
  6. */
  7. @AnyThread
  8. public List<AccessPoint> getAccessPoints() {
  9. synchronized (mLock) {
  10. return new ArrayList<>(mInternalAccessPoints);
  11. }
  12. }

接下来的过程最终还是会走到WifiManager.getScanResults,WifiServiceImpl.getScanResults,细节上会有差异。

 

一 前言

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!