• [Android]Android P(9) WIFI学习笔记 - 扫描 (2)


    前文回顾

    前言

    1. 基于Android P源码学习;
    2. 代码片为了方便阅读段经过删、裁减,请以实际源码为准;

    请求WLAN芯片开始扫描,然后获取扫描结果,整个过程是分两个阶段:

    1. 请求扫描
    2. 获取结果

    前者在上一篇中已经梳理过了,并且已经知晓,扫描完成后,App可以通过广播``,因此本篇会来梳理一下获取扫描结果的一个流程;

    获取扫描结果

    APP入口

    WifiManager
    //frameworks/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();
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    注意:

    1. 系统层如果出错,返回的结果是空列表,而不是null

    system_server层

    WifiServiceImpl
    //frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiServiceImpl.java
        @Override
        public List<ScanResult> getScanResults(String callingPackage) {
    		...
            try {
    			...
                final List<ScanResult> scanResults = new ArrayList<>();
                //切换到WifiStateMachine线程执行,并在当前线程等待其返回结果,超时设定默认4s;
                boolean success = mWifiInjector.getWifiStateMachineHandler().runWithScissors(() -> {
                    scanResults.addAll(mScanRequestProxy.getScanResults());
                }, RUN_WITH_SCISSORS_TIMEOUT_MILLIS);
    			...
    			//如果超时或者其他原因导致没获取到结果,此处返回一个空的ArrayList,而不是null;
                return scanResults;
            } catch (SecurityException e) {
                return new ArrayList<ScanResult>();
            } ...
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    抛开线程切换部分不讨论,上面主要的业务逻辑是将ScanRequestProxy.getScanResults()返回结果添加到scanResults变量中;
    那么来看ScanRequestProxy.getScanResults()的实现:

    ScanRequestProxy
    //frameworks/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;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    可见这里是直接从缓存数据中获取并返回,因此同步调用的逻辑到此就结束了;
    接下来,我们要从ScanRequestProxy这里开始,调查这个mLastScanResults是如何来的;

        private class ScanRequestProxyScanListener implements WifiScanner.ScanListener {
    		...
            @Override
            public void onResults(WifiScanner.ScanData[] scanDatas) {
    			...
                WifiScanner.ScanData scanData = scanDatas[0];
                ScanResult[] scanResults = scanData.getResults();
    			...
    			//将数据保存,并发送广播,提醒APP可以通过WifiManager.getScanResults()获取到新数据了;
                mLastScanResults.clear();
                mLastScanResults.addAll(Arrays.asList(scanResults));
                sendScanResultBroadcastIfScanProcessingNotComplete(true);
            }
    		...
        };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    这个ScanRequestProxyScanListener内部类的实例对象,是在startScan()是,构造并传递给WifiScanner的:

    	...
        public boolean startScan(int callingUid, String packageName) {
    		...
            mWifiScanner.startScan(settings, new ScanRequestProxyScanListener(), workSource);
    		...
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    WifiScanner
    //frameworks/base/wifi/java/android/net/wifi/WifiScanner.java
        private static final int INVALID_KEY = 0;
        private int mListenerKey = 1;
    
        private final SparseArray mListenerMap = new SparseArray();
        private final Object mListenerMapLock = new Object();
        ...
        public void startScan(ScanSettings settings, ScanListener listener, WorkSource workSource) {
    		...
            int key = addListener(listener);
            if (key == INVALID_KEY) return;
    		...
        }
        ...
        private int addListener(ActionListener listener) {
            synchronized (mListenerMapLock) {
                boolean keyExists = (getListenerKey(listener) != INVALID_KEY);
    			//无论是否存在重复listener,先添加
                int key = putListener(listener);
                if (keyExists) {
    				//如果存在,通知mInternalHandler执行removeListener逻辑;
                    OperationResult operationResult = new OperationResult(REASON_DUPLICATE_REQEUST,
                            "Outstanding request with same key not stopped yet");
                    Message message = Message.obtain(mInternalHandler, CMD_OP_FAILED, 0, key,
                            operationResult);
                    message.sendToTarget();
                    return INVALID_KEY;
                } else {
                    return key;
                }
            }
        }
    
    	private int putListener(Object listener) {
            if (listener == null) return INVALID_KEY;
            int key;
            synchronized (mListenerMapLock) {
                do {
                    key = mListenerKey++;
                } while (key == INVALID_KEY);
                mListenerMap.put(key, listener);
            }
            return key;
        }
        ...
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45

    上面其实就是一个结论:所有扫描请求传递过来的ScanListener均添加在WifiScanner内维护的SparseArray mListenerMap这个Map中;
    鉴于成员变量mListenerMap为私有变量,且并未提供外部获取接口,因此我们可以认为,其触发onResults也应该是在WifiScanner内完成的;
    比较简单,整个类中就只有ServiceHandler.handleMessage()中调用了ScanListener.onResults(),而成员变量mInternalHandler也就是ServiceHandler的实例对象:

        private final Handler mInternalHandler;
    
    	public WifiScanner(Context context, IWifiScanner service, Looper looper) {
    		...
    		mInternalHandler = new ServiceHandler(looper);
    		...
    	}
    	...
    	private class ServiceHandler extends Handler {
            ServiceHandler(Looper looper) {
                super(looper);
            }
            @Override
            public void handleMessage(Message msg) {
     			...
                Object listener = getListener(msg.arg2);
    
                if (listener == null) {
                    if (DBG) Log.d(TAG, "invalid listener key = " + msg.arg2);
                    return;
                } else {
                    if (DBG) Log.d(TAG, "listener key = " + msg.arg2);
                }
    
                switch (msg.what) {
                    //这就是上面提到的针对重复Listener的removeListener逻辑:
                    case CMD_OP_FAILED : {
                            OperationResult result = (OperationResult)msg.obj;
                            ((ActionListener) listener).onFailure(result.reason, result.description);
                            removeListener(msg.arg2);
                        }
                        break;
                    //这就是通知到ScanRequestProxyScanListener的逻辑:
                    case CMD_SCAN_RESULT :
                        ((ScanListener) listener).onResults(
                                ((ParcelableScanData) msg.obj).getResults());
                        return;
                    ...
                }
            }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40

    因为WifiScanner与其IWifiScanner的接口实现类之间采用AsyncChannel完成通信,那么我们仅需在对端搜索发送CMD_SCAN_RESULT消息的逻辑,即可继续追踪:

    WifiScanningServiceImpl
    //frameworks/opt/net/wifi/service/java/com/android/server/wifi/scanner/WifiScanningServiceImpl.java
    		...
            void reportScanResults(ScanData results) {
                ...
                ScanData[] allResults = new ScanData[] {results};
                //当前扫描伴随而来的监听,会在此处分发回调
                for (RequestInfo<ScanSettings> entry : mActiveScans) {
                	//根据请求本身的参数,过滤掉他们不该获取到的扫描结果
                	//因为扫描请求是有做合并的,因此此处需要判断一下:
                	//例如:某个扫描请求未指定扫描隐藏网络的参数,而此次扫描结果中包含隐藏网络,就应该在此处过滤掉
                    ScanData[] resultsToDeliver = ScanScheduleUtil.filterResultsForSettings(
                            mChannelHelper, allResults, entry.settings, -1);
                    WifiScanner.ParcelableScanData parcelableResultsToDeliver =
                            new WifiScanner.ParcelableScanData(resultsToDeliver);
                    logCallback("singleScanResults",  entry.clientInfo, entry.handlerId,
                            describeForLog(resultsToDeliver));
                    entry.reportEvent(WifiScanner.CMD_SCAN_RESULT, 0, parcelableResultsToDeliver);
                    // make sure the handler is removed
                    entry.reportEvent(WifiScanner.CMD_SINGLE_SCAN_COMPLETED, 0, null);
                }
    
                WifiScanner.ParcelableScanData parcelableAllResults =
                        new WifiScanner.ParcelableScanData(allResults);
                //通过WifiScanner.registerScanListener()注册的监听,会在此处分发回调
                for (RequestInfo<Void> entry : mSingleScanListeners) {
                    logCallback("singleScanResults",  entry.clientInfo, entry.handlerId,
                            describeForLog(allResults));
                    entry.reportEvent(WifiScanner.CMD_SCAN_RESULT, 0, parcelableAllResults);
                }
    
                if (results.isAllChannelsScanned()) {
                    mCachedScanResults.clear();
                    mCachedScanResults.addAll(Arrays.asList(results.getResults()));
                }
            }
            ...
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    而调用reportScanResults的调用在WifiSingleScanStateMachineWifiPnoScanStateMachine两个状态机中;

    由于我们到目前为止一直讨论的是前者,因此以WifiSingleScanStateMachine继续分析:

    //frameworks/opt/net/wifi/service/java/com/android/server/wifi/scanner/WifiScanningServiceImpl.java
    ...
            class ScanningState extends State {
    			...
                @Override
                public boolean processMessage(Message msg) {
                    switch (msg.what) {
                        case CMD_SCAN_RESULTS_AVAILABLE:
                            mWifiMetrics.incrementScanReturnEntry(
                                    WifiMetricsProto.WifiLog.SCAN_SUCCESS,
                                    mActiveScans.size());
                            reportScanResults(mScannerImpl.getLatestSingleScanResults());
                            mActiveScans.clear();
                            transitionTo(mIdleState);
                            return HANDLED;
                        ...
                    }
                }
            }
    ...
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    从这里,我们需要将代码分两个方向梳理:

    1. 发送CMD_SCAN_RESULTS_AVAILABLE消息的逻辑;

      class WifiSingleScanStateMachine extends StateMachine implements WifiNative.ScanEventHandler {
      	...
          @Override
          public void onScanStatus(int event) {
              if (DBG) localLog("onScanStatus event received, event=" + event);
              switch(event) {
                  case WifiNative.WIFI_SCAN_RESULTS_AVAILABLE:
                  case WifiNative.WIFI_SCAN_THRESHOLD_NUM_SCANS:
                  case WifiNative.WIFI_SCAN_THRESHOLD_PERCENT:
                      sendMessage(CMD_SCAN_RESULTS_AVAILABLE);
                      break;
      			...
              }
          }
          ...
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16

      由于当前设备不支持后台扫描(Background Scan)因此会回调onScanStatus(WIFI_SCAN_RESULTS_AVAILABLE)的逻辑来自WificondScannerImpl.pollLatestScanData(),这里我们先在此打住,因为后面那条分析方向,也会走到这里来;

    2. 调用mScannerImpl.getLatestSingleScanResults()的逻辑;

      成员变量mScannerImpl的类型为WifiScannerImpl,由上一篇我们知道,WifiScannerImpl的实现类是按照工厂设计模式来选择的,当前手边设备普遍构造的是WificondScannerImpl,因此我们查看其内部getLatestSingleScanResults()的实现:

      WificondScannerImpl
      //frameworks/opt/net/wifi/service/java/com/android/server/wifi/scanner/WificondScannerImpl.java
          @Override
          public WifiScanner.ScanData getLatestSingleScanResults() {
              return mLatestSingleScanResult;
          }
      
      • 1
      • 2
      • 3
      • 4
      • 5

      再一次,直接返回的缓存数据,那么我们以此为基础,再来看看成员变量mLatestSingleScanResult的数据填充逻辑:

          private void pollLatestScanData() {
              synchronized (mSettingsLock) {
                  //上一节我们提到过,startSingleScan时,如果该成员变量为null,会构造该成员变量,避免重复请求
                  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;
                  //将Native返回数据进行重新封装、过滤;
                  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++;
                      }
                  }
                  if (numFilteredScanResults != 0) {
                      Log.d(TAG, "Filtering out " + numFilteredScanResults + " scan results.");
                  }
      
                  if (mLastScanSettings.singleScanEventHandler != null) {
                      if (mLastScanSettings.reportSingleScanFullResults) {
                          for (ScanResult scanResult : singleScanResults) {
                              // ignore buckets scanned since there is only one bucket for a single scan
                              mLastScanSettings.singleScanEventHandler.onFullScanResult(scanResult,
                                      /* bucketsScanned */ 0);
                          }
                      }
                      //按信号强弱排序
                      Collections.sort(singleScanResults, SCAN_RESULT_SORT_COMPARATOR);
                      //构造并填充mLatestSingleScanResult的数据
                      mLatestSingleScanResult = new WifiScanner.ScanData(0, 0, 0,
                              isAllChannelsScanned(mLastScanSettings.singleScanFreqs),
                              singleScanResults.toArray(new ScanResult[singleScanResults.size()]));
                      mLastScanSettings.singleScanEventHandler
                              .onScanStatus(WifiNative.WIFI_SCAN_RESULTS_AVAILABLE);
                  }
      
                  mLastScanSettings = null;
              }
          }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
      • 34
      • 35
      • 36
      • 37
      • 38
      • 39
      • 40
      • 41
      • 42
      • 43
      • 44
      • 45
      • 46
      • 47
      • 48
      • 49
      • 50
      • 51

    同样,我们分两个方向梳理:

    1. 调用pollLatestScanData的逻辑;

          @Override
          public boolean handleMessage(Message msg) {
              switch(msg.what) {
      			...
                  case WifiMonitor.SCAN_RESULTS_EVENT:
                      cancelScanTimeout();
                      pollLatestScanData();
                      break;
      			...
              }
              return true;
          }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12

      发送WifiMonitor.SCAN_RESULTS_EVENT消息的逻辑来自WifiMonitor

      WifiMonitor
      //frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiMonitor.java
      public void broadcastScanResultEvent(String iface) {
          sendMessage(iface, SCAN_RESULTS_EVENT);
      }
      
      • 1
      • 2
      • 3
      • 4

      调用broadcastScanResultEvent则来自WificondControl

      WificondControl
      //frameworks/opt/net/wifi/service/java/com/android/server/wifi/WificondControl.java
      private class ScanEventHandler extends IScanEvent.Stub {
          private String mIfaceName;
      
          ScanEventHandler(@NonNull String ifaceName) {
              mIfaceName = ifaceName;
          }
      
          @Override
          public void OnScanResultReady() {
              Log.d(TAG, "Scan result ready event");
              mWifiMonitor.broadcastScanResultEvent(mIfaceName);
          }
      
          @Override
          public void OnScanFailed() {
              Log.d(TAG, "Scan failed event");
              mWifiMonitor.broadcastScanFailedEvent(mIfaceName);
          }
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20

      关于ScanEventHandler的实例对象,会在setupInterfaceForClientMode时被构造,并通过HIDL接口注册到HAL层:

      public IClientInterface setupInterfaceForClientMode(@NonNull String ifaceName) {
      	...
      
          IClientInterface clientInterface = null;
          try {
              clientInterface = mWificond.createClientInterface(ifaceName);
          } catch (RemoteException e1) {
              Log.e(TAG, "Failed to get IClientInterface due to remote exception");
              return null;
          }
      
      	...
      
          // 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);
      		...
          } catch (RemoteException e) {
              Log.e(TAG, "Failed to refresh wificond scanner due to remote exception");
          }
      
          return clientInterface;
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33

      setupInterfaceForClientMode会在打开WLAN时调用,这里就不赘述了;
      IWifiScannerImpl.subscribeScanEvents()及其回调ScanEventHandler.OnScanResultReady也是在wificond进程内实现并完成的,这里也暂不讨论;
      综上,这条逻辑链路已经梳理完毕,我们回到pollLatestScanData方法,看看向下调用的逻辑:

    2. pollLatestScanData方法内部核心业务逻辑WifiNative.getScanResults()的实现;

      WifiNative
      //frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiNative.java
          public ArrayList<ScanDetail> getScanResults(@NonNull String ifaceName) {
              return mWificondControl.getScanResults(
                      ifaceName, WificondControl.SCAN_TYPE_SINGLE_SCAN);
          }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      WificondControl
      //frameworks/opt/net/wifi/service/java/com/android/server/wifi/WificondControl.java
      	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();
                  }
                  for (NativeScanResult result : nativeResults) {
                      WifiSsid wifiSsid = WifiSsid.createFromByteArray(result.ssid);
                      String bssid;
                      try {
                          bssid = NativeUtil.macAddressFromByteArray(result.bssid);
                      } catch (IllegalArgumentException e) {
                          Log.e(TAG, "Illegal argument " + result.bssid, e);
                          continue;
                      }
                      if (bssid == null) {
                          Log.e(TAG, "Illegal null bssid");
                          continue;
                      }
                      ScanResult.InformationElement[] ies =
                              InformationElementUtil.parseInformationElements(result.infoElement);
                      InformationElementUtil.Capabilities capabilities =
                              new InformationElementUtil.Capabilities();
                      capabilities.from(ies, result.capability);
                      String flags = capabilities.generateCapabilitiesString();
                      NetworkDetail networkDetail;
                      try {
                          networkDetail = new NetworkDetail(bssid, ies, null, result.frequency);
                      } catch (IllegalArgumentException e) {
                          Log.e(TAG, "Illegal argument for scan result with bssid: " + bssid, e);
                          continue;
                      }
      
                      ScanDetail scanDetail = new ScanDetail(networkDetail, wifiSsid, bssid, flags,
                              result.signalMbm / 100, result.frequency, result.tsf, ies, null);
                      ScanResult scanResult = scanDetail.getScanResult();
                      // Update carrier network info if this AP's SSID is associated with a carrier Wi-Fi
                      // network and it uses EAP.
                      if (ScanResultUtil.isScanResultForEapNetwork(scanDetail.getScanResult())
                              && mCarrierNetworkConfig.isCarrierNetwork(wifiSsid.toString())) {
                          scanResult.isCarrierAp = true;
                          scanResult.carrierApEapType =
                                  mCarrierNetworkConfig.getNetworkEapType(wifiSsid.toString());
                          scanResult.carrierName =
                                  mCarrierNetworkConfig.getCarrierName(wifiSsid.toString());
                      }
                      // Fill up the radio chain info.
                      if (result.radioChainInfos != null) {
                          scanResult.radioChainInfos =
                              new ScanResult.RadioChainInfo[result.radioChainInfos.size()];
                          int idx = 0;
                          for (RadioChainInfo nativeRadioChainInfo : result.radioChainInfos) {
                              scanResult.radioChainInfos[idx] = new ScanResult.RadioChainInfo();
                              scanResult.radioChainInfos[idx].id = nativeRadioChainInfo.chainId;
                              scanResult.radioChainInfos[idx].level = nativeRadioChainInfo.level;
                              idx++;
                          }
                      }
                      results.add(scanDetail);
                  }
              } catch (RemoteException e1) {
                  Log.e(TAG, "Failed to create ScanDetail ArrayList");
              }
              if (mVerboseLoggingEnabled) {
                  Log.d(TAG, "get " + results.size() + " scan results from wificond");
              }
      
              return results;
          }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
      • 34
      • 35
      • 36
      • 37
      • 38
      • 39
      • 40
      • 41
      • 42
      • 43
      • 44
      • 45
      • 46
      • 47
      • 48
      • 49
      • 50
      • 51
      • 52
      • 53
      • 54
      • 55
      • 56
      • 57
      • 58
      • 59
      • 60
      • 61
      • 62
      • 63
      • 64
      • 65
      • 66
      • 67
      • 68
      • 69
      • 70
      • 71
      • 72
      • 73
      • 74
      • 75
      • 76
      • 77
      • 78

      上一篇我们知道,IWifiScannerImpl的实现类,在wificond进程内,已经超出了Framework的范畴,故在此打住,后续有需求,再从wificond触发来梳理;

    总结

    截至目前的逻辑链路已经能满足日常工作需要的知识储备;

    简单总结一下:

    1. 扫描结果就绪后,wificond会通过AIDL接口ScanEventHandler.OnScanResultReady回调给到WifiCondControl,并通知其调用IWifiScannerImpl.getScanResult()获取扫描结果,将其保存到WificondScannerImpl.mLatestSingleScanResult
    2. 后续获取扫描结果的请求都不是实时从wificond获取的;
    3. 同时,在一步一步回调之后,ScanRequestProxy内也会维护一份扫描结果mLastScanResults
    4. 为什么会存在两套缓存机制,这里我个人理解如下:
      • ScanRequestProxy.mLastScanResults相对而言是作为前端缓存,直接对接WifiServiceImpl的,用于直接返回,缓存的目的是快速返回;
      • WificondScannerImpl.mLatestSingleScanResult则更像一个后端缓存,用来缓存上一次从wificond获取到的扫描结果,其缓存的目的也不太一样:
        • 一是用来与当前扫描请求参数做匹配,如果当前扫描结果不满足扫描请求的参数,则会触发下一次扫描;
        • 二是可以对接不同的扫描请求类型,即通过扫描请求的参数,过滤对应的扫描结果,并将不同的扫描结果通知给到前端;

    最后老规矩,附上流程图一份:
    获取扫描结果流程图

  • 相关阅读:
    Nginx 反向代理 SSL 证书绑定域名
    Linux常见命令总结
    vulhub venom
    ubuntu/windows/mac小问题记录
    实验送样、数据分析样品、组名命名规范
    『手撕 Mybatis 源码』05 - SqlSession 执行主流程
    智能指针、单件模式、函数式编程、c/c++
    AWS 中文入门开发教学 39- AWS CLI - AWS认证 必须会的命令行工具
    前端css粘性布局,顶部吸附效果(position: sticky)
    如何删除清理Mac“其他”文件并删除它
  • 原文地址:https://blog.csdn.net/u014175785/article/details/126664796