编程语言
首页 > 编程语言> > [转载] Wifi模块—源码分析Wifi热点扫描(Android P)

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

作者:互联网

原文链接: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的构造函数。

  1. ClientModeStateMachine(Looper looper) {
  2. super(TAG, looper);
  3. addState(mIdleState);
  4. addState(mStartedState);
  5. setInitialState(mIdleState);
  6. start();
  7. }

再看start()。

  1. /**
  2. * Start client mode.
  3. */
  4. public void start() {
  5. mStateMachine.sendMessage(ClientModeStateMachine.CMD_START);
  6. }

发送了一个消息ClientModeStateMachine.CMD_START。

  1. private class IdleState extends State {
  2. @Override
  3. public void enter() {
  4. Log.d(TAG, "entering IdleState");
  5. mClientInterfaceName = null;
  6. mIfaceIsUp = false;
  7. }
  8. @Override
  9. public boolean processMessage(Message message) {
  10. switch (message.what) {
  11. case CMD_START:
  12. updateWifiState(WifiManager.WIFI_STATE_ENABLING,
  13. WifiManager.WIFI_STATE_DISABLED);
  14. mClientInterfaceName = mWifiNative.setupInterfaceForClientMode(false /* not low priority */, mWifiNativeInterfaceCallback);
  15. if (TextUtils.isEmpty(mClientInterfaceName)) {
  16. Log.e(TAG, "Failed to create ClientInterface. Sit in Idle");
  17. updateWifiState(WifiManager.WIFI_STATE_UNKNOWN,
  18. WifiManager.WIFI_STATE_ENABLING);
  19. updateWifiState(WifiManager.WIFI_STATE_DISABLED,
  20. WifiManager.WIFI_STATE_UNKNOWN);
  21. break;
  22. }
  23. sendScanAvailableBroadcast(false);
  24. mScanRequestProxy.enableScanningForHiddenNetworks(false);
  25. mScanRequestProxy.clearScanResults();
  26. transitionTo(mStartedState);
  27. break;
  28. default:
  29. Log.d(TAG, "received an invalid message: " + message);
  30. return NOT_HANDLED;
  31. }
  32. return HANDLED;
  33. }
  34. }

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

  1. /**
  2. * Update Wifi state and send the broadcast.
  3. * @param newState new Wifi state
  4. * @param currentState current wifi state
  5. */
  6. private void updateWifiState(int newState, int currentState) {
  7. if (!mExpectedStop) {
  8. mListener.onStateChanged(newState);
  9. } else {
  10. Log.d(TAG, "expected stop, not triggering callbacks: newState = "
  11. + newState);
  12. }
  13. // Once we report the mode has stopped/failed any other stop signals are redundant
  14. // note: this can happen in failure modes where we get multiple callbacks as underlying
  15. // components/interface stops or the underlying interface is destroyed in cleanup
  16. if (newState == WifiManager.WIFI_STATE_UNKNOWN
  17. || newState == WifiManager.WIFI_STATE_DISABLED) {
  18. mExpectedStop = true;
  19. }
  20. if (newState == WifiManager.WIFI_STATE_UNKNOWN) {
  21. // do not need to broadcast failure to system
  22. return;
  23. }
  24. mWifiStateMachine.setWifiStateForApiCalls(newState);
  25. final Intent intent = new Intent(WifiManager.WIFI_STATE_CHANGED_ACTION);
  26. intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
  27. intent.putExtra(WifiManager.EXTRA_WIFI_STATE, newState);
  28. intent.putExtra(WifiManager.EXTRA_PREVIOUS_WIFI_STATE, currentState);
  29. mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
  30. }

在这里发送了一个广播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。

  1. @Override
  2. public void onActivityCreated(Bundle savedInstanceState) {
  3. super.onActivityCreated(savedInstanceState);
  4. mWifiTracker = WifiTrackerFactory.create(
  5. getActivity(), this, getLifecycle(), true, true);
  6. mWifiManager = mWifiTracker.getManager();
  7. ...
  8. }

   

1.2 packages/apps/Settings/src/com/android/settings/wifi/WifiEnabler.java

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

  1. private boolean mStateMachineEvent;
  2. private final IntentFilter mIntentFilter;
  3. private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
  4. @Override
  5. public void onReceive(Context context, Intent intent) {
  6. String action = intent.getAction();
  7. if (WifiManager.WIFI_STATE_CHANGED_ACTION.equals(action)) {
  8. handleWifiStateChanged(mWifiManager.getWifiState());
  9. } else if (WifiManager.SUPPLICANT_STATE_CHANGED_ACTION.equals(action)) {
  10. if (!mConnected.get()) {
  11. handleStateChanged(WifiInfo.getDetailedStateOf((SupplicantState)
  12. intent.getParcelableExtra(WifiManager.EXTRA_NEW_STATE)));
  13. }
  14. } else if (WifiManager.NETWORK_STATE_CHANGED_ACTION.equals(action)) {
  15. NetworkInfo info = (NetworkInfo) intent.getParcelableExtra(
  16. WifiManager.EXTRA_NETWORK_INFO);
  17. mConnected.set(info.isConnected());
  18. handleStateChanged(info.getDetailedState());
  19. }
  20. }
  21. };

看handleWifiStateChanged。

  1. private void handleWifiStateChanged(int state) {
  2. // Clear any previous state
  3. mSwitchWidget.setDisabledByAdmin(null);
  4. switch (state) {
  5. case WifiManager.WIFI_STATE_ENABLING:
  6. break;
  7. case WifiManager.WIFI_STATE_ENABLED:
  8. setSwitchBarChecked(true);
  9. mSwitchWidget.setEnabled(true);
  10. break;
  11. case WifiManager.WIFI_STATE_DISABLING:
  12. break;
  13. case WifiManager.WIFI_STATE_DISABLED:
  14. setSwitchBarChecked(false);
  15. mSwitchWidget.setEnabled(true);
  16. break;
  17. default:
  18. setSwitchBarChecked(false);
  19. mSwitchWidget.setEnabled(true);
  20. }
  21. if (RestrictedLockUtils.hasBaseUserRestriction(mContext,
  22. UserManager.DISALLOW_CONFIG_TETHERING, UserHandle.myUserId())) {
  23. mSwitchWidget.setEnabled(false);
  24. } else {
  25. final EnforcedAdmin admin = RestrictedLockUtils.checkIfRestrictionEnforced(mContext,
  26. UserManager.DISALLOW_CONFIG_TETHERING, UserHandle.myUserId());
  27. mSwitchWidget.setDisabledByAdmin(admin);
  28. }
  29. }

根据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

  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(intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
  13. WifiManager.WIFI_STATE_UNKNOWN));
  14. } else if (WifiManager.SCAN_RESULTS_AVAILABLE_ACTION.equals(action)) {
  15. mStaleScanResults = false;
  16. fetchScansAndConfigsAndUpdateAccessPoints();
  17. } else if (WifiManager.CONFIGURED_NETWORKS_CHANGED_ACTION.equals(action)
  18. || WifiManager.LINK_CONFIGURATION_CHANGED_ACTION.equals(action)) {
  19. fetchScansAndConfigsAndUpdateAccessPoints();
  20. } else if (WifiManager.NETWORK_STATE_CHANGED_ACTION.equals(action)) {
  21. // TODO(sghuman): Refactor these methods so they cannot result in duplicate
  22. // onAccessPointsChanged updates being called from this intent.
  23. NetworkInfo info = intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
  24. updateNetworkInfo(info);
  25. fetchScansAndConfigsAndUpdateAccessPoints();
  26. } else if (WifiManager.RSSI_CHANGED_ACTION.equals(action)) {
  27. NetworkInfo info =
  28. mConnectivityManager.getNetworkInfo(mWifiManager.getCurrentNetwork());
  29. updateNetworkInfo(info);
  30. }
  31. }
  32. };

看updateWifiState。

  1. /**
  2. * Handles updates to WifiState.
  3. *
  4. * <p>If Wifi is not enabled in the enabled state, {@link #mStaleScanResults} will be set to
  5. * true.
  6. */
  7. private void updateWifiState(int state) {
  8. if (state == WifiManager.WIFI_STATE_ENABLED) {
  9. if (mScanner != null) {
  10. // We only need to resume if mScanner isn't null because
  11. // that means we want to be scanning.
  12. mScanner.resume();
  13. }
  14. } else {
  15. clearAccessPointsAndConditionallyUpdate();
  16. mLastInfo = null;
  17. mLastNetworkInfo = null;
  18. if (mScanner != null) {
  19. mScanner.pause();
  20. }
  21. mStaleScanResults = true;
  22. }
  23. mListener.onWifiStateChanged(state);
  24. }

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

  1. @VisibleForTesting
  2. class Scanner extends Handler {
  3. static final int MSG_SCAN = 0;
  4. private int mRetry = 0;
  5. void resume() {
  6. if (!hasMessages(MSG_SCAN)) {
  7. sendEmptyMessage(MSG_SCAN);
  8. }
  9. }
  10. void pause() {
  11. mRetry = 0;
  12. removeMessages(MSG_SCAN);
  13. }
  14. @VisibleForTesting
  15. boolean isScanning() {
  16. return hasMessages(MSG_SCAN);
  17. }
  18. @Override
  19. public void handleMessage(Message message) {
  20. if (message.what != MSG_SCAN) return;
  21. if (mWifiManager.startScan()) {
  22. mRetry = 0;
  23. } else if (++mRetry >= 3) {
  24. mRetry = 0;
  25. if (mContext != null) {
  26. Toast.makeText(mContext, R.string.wifi_fail_to_scan, Toast.LENGTH_LONG).show();
  27. }
  28. return;
  29. }
  30. sendEmptyMessageDelayed(MSG_SCAN, WIFI_RESCAN_INTERVAL_MS);
  31. }
  32. }

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

 

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

  1. * <p>
  2. * To initiate a Wi-Fi scan, declare the
  3. * {@link android.Manifest.permission#CHANGE_WIFI_STATE}
  4. * permission in the manifest, and perform these steps:
  5. * </p>
  6. * <ol style="1">
  7. * <li>Invoke the following method:
  8. * {@code ((WifiManager) getSystemService(WIFI_SERVICE)).startScan()}</li>
  9. * <li>
  10. * Register a BroadcastReceiver to listen to
  11. * {@code SCAN_RESULTS_AVAILABLE_ACTION}.</li>
  12. * <li>When a broadcast is received, call:
  13. * {@code ((WifiManager) getSystemService(WIFI_SERVICE)).getScanResults()}</li>
  14. * </ol>
  15. * @return {@code true} if the operation succeeded, i.e., the scan was initiated.
  16. * @deprecated The ability for apps to trigger scan requests will be removed in a future
  17. * release.
  18. */
  19. @Deprecated
  20. public boolean startScan() {
  21. return startScan(null);
  22. }
  23. /** @hide */
  24. @SystemApi
  25. @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS)
  26. public boolean startScan(WorkSource workSource) {
  27. try {
  28. String packageName = mContext.getOpPackageName();
  29. return mService.startScan(packageName);
  30. } catch (RemoteException e) {
  31. throw e.rethrowFromSystemServer();
  32. }
  33. }

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

 

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

  1. /**
  2. * See {@link android.net.wifi.WifiManager#startScan}
  3. *
  4. * @param packageName Package name of the app that requests wifi scan.
  5. */
  6. @Override
  7. public boolean startScan(String packageName) {
  8. if (enforceChangePermission(packageName) != MODE_ALLOWED) {
  9. return false;
  10. }
  11. int callingUid = Binder.getCallingUid();
  12. long ident = Binder.clearCallingIdentity();
  13. mLog.info("startScan uid=%").c(callingUid).flush();
  14. synchronized (this) {
  15. if (mInIdleMode) {
  16. // Need to send an immediate scan result broadcast in case the
  17. // caller is waiting for a result ..
  18. // TODO: investigate if the logic to cancel scans when idle can move to
  19. // WifiScanningServiceImpl. This will 1 - clean up WifiServiceImpl and 2 -
  20. // avoid plumbing an awkward path to report a cancelled/failed scan. This will
  21. // be sent directly until b/31398592 is fixed.
  22. sendFailedScanBroadcast();
  23. mScanPending = true;
  24. return false;
  25. }
  26. }
  27. try {
  28. mWifiPermissionsUtil.enforceCanAccessScanResults(packageName, callingUid);
  29. Mutable<Boolean> scanSuccess = new Mutable<>();
  30. boolean runWithScissorsSuccess = mWifiInjector.getWifiStateMachineHandler()
  31. .runWithScissors(() -> {
  32. scanSuccess.value = mScanRequestProxy.startScan(callingUid, packageName);
  33. }, RUN_WITH_SCISSORS_TIMEOUT_MILLIS);
  34. if (!runWithScissorsSuccess) {
  35. Log.e(TAG, "Failed to post runnable to start scan");
  36. sendFailedScanBroadcast();
  37. return false;
  38. }
  39. if (!scanSuccess.value) {
  40. Log.e(TAG, "Failed to start scan");
  41. return false;
  42. }
  43. } catch (SecurityException e) {
  44. return false;
  45. } finally {
  46. Binder.restoreCallingIdentity(ident);
  47. }
  48. return true;
  49. }

继续看mScanRequestProxy.startScan。

 

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

  1. /**
  2. * Initiate a wifi scan.
  3. *
  4. * @param callingUid The uid initiating the wifi scan. Blame will be given to this uid.
  5. * @return true if the scan request was placed or a scan is already ongoing, false otherwise.
  6. */
  7. public boolean startScan(int callingUid, String packageName) {
  8. if (!retrieveWifiScannerIfNecessary()) {
  9. Log.e(TAG, "Failed to retrieve wifiscanner");
  10. sendScanResultFailureBroadcastToPackage(packageName);
  11. return false;
  12. }
  13. boolean fromSettingsOrSetupWizard =
  14. mWifiPermissionsUtil.checkNetworkSettingsPermission(callingUid)
  15. || mWifiPermissionsUtil.checkNetworkSetupWizardPermission(callingUid);
  16. // Check and throttle scan request from apps without NETWORK_SETTINGS permission.
  17. if (!fromSettingsOrSetupWizard
  18. && shouldScanRequestBeThrottledForApp(callingUid, packageName)) {
  19. Log.i(TAG, "Scan request from " + packageName + " throttled");
  20. sendScanResultFailureBroadcastToPackage(packageName);
  21. return false;
  22. }
  23. // Create a worksource using the caller's UID.
  24. WorkSource workSource = new WorkSource(callingUid);
  25. // Create the scan settings.
  26. WifiScanner.ScanSettings settings = new WifiScanner.ScanSettings();
  27. // Scan requests from apps with network settings will be of high accuracy type.
  28. if (fromSettingsOrSetupWizard) {
  29. settings.type = WifiScanner.TYPE_HIGH_ACCURACY;
  30. }
  31. // always do full scans
  32. settings.band = WifiScanner.WIFI_BAND_BOTH_WITH_DFS;
  33. settings.reportEvents = WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN
  34. | WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT;
  35. if (mScanningForHiddenNetworksEnabled) {
  36. // retrieve the list of hidden network SSIDs to scan for, if enabled.
  37. List<WifiScanner.ScanSettings.HiddenNetwork> hiddenNetworkList =
  38. mWifiConfigManager.retrieveHiddenNetworkList();
  39. settings.hiddenNetworks = hiddenNetworkList.toArray(
  40. new WifiScanner.ScanSettings.HiddenNetwork[hiddenNetworkList.size()]);
  41. }
  42. mWifiScanner.startScan(settings, new ScanRequestProxyScanListener(), workSource);
  43. mIsScanProcessingComplete = false;
  44. return true;
  45. }

看mWifiScanner.startScan

 

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

  1. /**
  2. * starts a single scan and reports results asynchronously
  3. * @param settings specifies various parameters for the scan; for more information look at
  4. * {@link ScanSettings}
  5. * @param listener specifies the object to report events to. This object is also treated as a
  6. * key for this scan, and must also be specified to cancel the scan. Multiple
  7. * scans should also not share this object.
  8. */
  9. @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
  10. public void startScan(ScanSettings settings, ScanListener listener) {
  11. startScan(settings, listener, null);
  12. }
  13. /**
  14. * starts a single scan and reports results asynchronously
  15. * @param settings specifies various parameters for the scan; for more information look at
  16. * {@link ScanSettings}
  17. * @param workSource WorkSource to blame for power usage
  18. * @param listener specifies the object to report events to. This object is also treated as a
  19. * key for this scan, and must also be specified to cancel the scan. Multiple
  20. * scans should also not share this object.
  21. */
  22. @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
  23. public void startScan(ScanSettings settings, ScanListener listener, WorkSource workSource) {
  24. Preconditions.checkNotNull(listener, "listener cannot be null");
  25. int key = addListener(listener);
  26. if (key == INVALID_KEY) return;
  27. validateChannel();
  28. Bundle scanParams = new Bundle();
  29. scanParams.putParcelable(SCAN_PARAMS_SCAN_SETTINGS_KEY, settings);
  30. scanParams.putParcelable(SCAN_PARAMS_WORK_SOURCE_KEY, workSource);
  31. mAsyncChannel.sendMessage(CMD_START_SINGLE_SCAN, 0, key, scanParams);
  32. }

        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

  1. private class ClientHandler extends WifiHandler {
  2. ClientHandler(String tag, Looper looper) {
  3. super(tag, looper);
  4. }
  5. @Override
  6. public void handleMessage(Message msg) {
  7. super.handleMessage(msg);
  8. ...
  9. switch (msg.what) {
  10. case WifiScanner.CMD_START_BACKGROUND_SCAN:
  11. case WifiScanner.CMD_STOP_BACKGROUND_SCAN:
  12. mBackgroundScanStateMachine.sendMessage(Message.obtain(msg));
  13. break;
  14. case WifiScanner.CMD_START_PNO_SCAN:
  15. case WifiScanner.CMD_STOP_PNO_SCAN:
  16. mPnoScanStateMachine.sendMessage(Message.obtain(msg));
  17. break;
  18. case WifiScanner.CMD_START_SINGLE_SCAN:
  19. case WifiScanner.CMD_STOP_SINGLE_SCAN:
  20. mSingleScanStateMachine.sendMessage(Message.obtain(msg));
  21. break;
  22. ...
  23. }
  24. }
  25. }

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

  1. /**
  2. * State machine that holds the state of single scans. Scans should only be active in the
  3. * ScanningState. The pending scans and active scans maps are swapped when entering
  4. * ScanningState. Any requests queued while scanning will be placed in the pending queue and
  5. * executed after transitioning back to IdleState.
  6. */
  7. class WifiSingleScanStateMachine extends StateMachine implements WifiNative.ScanEventHandler {
  8. /**
  9. * Maximum age of results that we return from our cache via
  10. * {@link WifiScanner#getScanResults()}.
  11. * This is currently set to 3 minutes to restore parity with the wpa_supplicant's scan
  12. * result cache expiration policy. (See b/62253332 for details)
  13. */
  14. @VisibleForTesting
  15. public static final int CACHED_SCAN_RESULTS_MAX_AGE_IN_MILLIS = 180 * 1000;
  16. private final DefaultState mDefaultState = new DefaultState();
  17. private final DriverStartedState mDriverStartedState = new DriverStartedState();
  18. private final IdleState mIdleState = new IdleState();
  19. private final ScanningState mScanningState = new ScanningState();
  20. private WifiNative.ScanSettings mActiveScanSettings = null;
  21. private RequestList<ScanSettings> mActiveScans = new RequestList<>();
  22. private RequestList<ScanSettings> mPendingScans = new RequestList<>();
  23. // Scan results cached from the last full single scan request.
  24. private final List<ScanResult> mCachedScanResults = new ArrayList<>();
  25. WifiSingleScanStateMachine(Looper looper) {
  26. super("WifiSingleScanStateMachine", looper);
  27. setLogRecSize(128);
  28. setLogOnlyTransitions(false);
  29. // CHECKSTYLE:OFF IndentationCheck
  30. addState(mDefaultState);
  31. addState(mDriverStartedState, mDefaultState);
  32. addState(mIdleState, mDriverStartedState);
  33. addState(mScanningState, mDriverStartedState);
  34. // CHECKSTYLE:ON IndentationCheck
  35. setInitialState(mDefaultState);
  36. }
  37. ...
  38. }

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

  1. /**
  2. * State representing when the driver is running. This state is not meant to be transitioned
  3. * directly, but is instead intended as a parent state of ScanningState and IdleState
  4. * to hold common functionality and handle cleaning up scans when the driver is shut down.
  5. */
  6. class DriverStartedState extends State {
  7. ...
  8. @Override
  9. public boolean processMessage(Message msg) {
  10. ClientInfo ci = mClients.get(msg.replyTo);
  11. switch (msg.what) {
  12. case CMD_DRIVER_LOADED:
  13. // Ignore if we're already in driver loaded state.
  14. return HANDLED;
  15. case WifiScanner.CMD_START_SINGLE_SCAN:
  16. mWifiMetrics.incrementOneshotScanCount();
  17. int handler = msg.arg2;
  18. Bundle scanParams = (Bundle) msg.obj;
  19. if (scanParams == null) {
  20. logCallback("singleScanInvalidRequest", ci, handler, "null params");
  21. replyFailed(msg, WifiScanner.REASON_INVALID_REQUEST, "params null");
  22. return HANDLED;
  23. }
  24. scanParams.setDefusable(true);
  25. ScanSettings scanSettings =
  26. scanParams.getParcelable(WifiScanner.SCAN_PARAMS_SCAN_SETTINGS_KEY);
  27. WorkSource workSource =
  28. scanParams.getParcelable(WifiScanner.SCAN_PARAMS_WORK_SOURCE_KEY);
  29. if (validateScanRequest(ci, handler, scanSettings)) {
  30. logScanRequest("addSingleScanRequest", ci, handler, workSource,
  31. scanSettings, null);
  32. replySucceeded(msg);
  33. // If there is an active scan that will fulfill the scan request then
  34. // mark this request as an active scan, otherwise mark it pending.
  35. // If were not currently scanning then try to start a scan. Otherwise
  36. // this scan will be scheduled when transitioning back to IdleState
  37. // after finishing the current scan.
  38. if (getCurrentState() == mScanningState) {
  39. if (activeScanSatisfies(scanSettings)) {
  40. mActiveScans.addRequest(ci, handler, workSource, scanSettings);
  41. } else {
  42. mPendingScans.addRequest(ci, handler, workSource, scanSettings);
  43. }
  44. } else {
  45. mPendingScans.addRequest(ci, handler, workSource, scanSettings);
  46. tryToStartNewScan();
  47. }
  48. } else {
  49. ...
  50. }
  51. }
  52. }
  53. }

看调用的tryToStartNewScan。

  1. void tryToStartNewScan() {
  2. if (mPendingScans.size() == 0) { // no pending requests
  3. return;
  4. }
  5. ...
  6. if (mScannerImpl.startSingleScan(settings, this)) {
  7. // store the active scan settings
  8. mActiveScanSettings = settings;
  9. // swap pending and active scan requests
  10. RequestList<ScanSettings> tmp = mActiveScans;
  11. mActiveScans = mPendingScans;
  12. mPendingScans = tmp;
  13. // make sure that the pending list is clear
  14. mPendingScans.clear();
  15. transitionTo(mScanningState);
  16. } else {
  17. mWifiMetrics.incrementScanReturnEntry(
  18. WifiMetricsProto.WifiLog.SCAN_UNKNOWN, mPendingScans.size());
  19. // notify and cancel failed scans
  20. sendOpFailedToAllAndClear(mPendingScans, WifiScanner.REASON_UNSPECIFIED,
  21. "Failed to start single scan");
  22. }
  23. }

看mScannerImpl.startSingleScan。

 

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

  1. /**
  2. * Start a one time scan. This method should only be called when there is no scan going on
  3. * (after a callback indicating that the previous scan succeeded/failed).
  4. * @return if the scan paramaters are valid
  5. * Note this may return true even if the parameters are not accepted by the chip because the
  6. * scan may be scheduled async.
  7. */
  8. public abstract boolean startSingleScan(WifiNative.ScanSettings settings,
  9. WifiNative.ScanEventHandler eventHandler);

 

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

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

  1. @Override
  2. public boolean startSingleScan(WifiNative.ScanSettings settings,
  3. WifiNative.ScanEventHandler eventHandler) {
  4. ...
  5. if (!allFreqs.isEmpty()) {
  6. freqs = allFreqs.getScanFreqs();
  7. success = mWifiNative.scan(
  8. mIfaceName, settings.scanType, freqs, hiddenNetworkSSIDSet);
  9. if (!success) {
  10. Log.e(TAG, "Failed to start scan, freqs=" + freqs);
  11. }
  12. } else {
  13. // There is a scan request but no available channels could be scanned for.
  14. // We regard it as a scan failure in this case.
  15. Log.e(TAG, "Failed to start scan because there is no available channel to scan");
  16. }
  17. if (success) {
  18. if (DBG) {
  19. Log.d(TAG, "Starting wifi scan for freqs=" + freqs);
  20. }
  21. mScanTimeoutListener = new AlarmManager.OnAlarmListener() {
  22. @Override public void onAlarm() {
  23. handleScanTimeout();
  24. }
  25. };
  26. mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
  27. mClock.getElapsedSinceBootMillis() + SCAN_TIMEOUT_MS,
  28. TIMEOUT_ALARM_TAG, mScanTimeoutListener, mEventHandler);
  29. } else {
  30. // indicate scan failure async
  31. mEventHandler.post(new Runnable() {
  32. @Override public void run() {
  33. reportScanFailure();
  34. }
  35. });
  36. }
  37. return true;
  38. }
  39. }

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

 

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

  1. /**
  2. * Start a scan using wificond for the given parameters.
  3. * @param ifaceName Name of the interface.
  4. * @param scanType Type of scan to perform. One of {@link ScanSettings#SCAN_TYPE_LOW_LATENCY},
  5. * {@link ScanSettings#SCAN_TYPE_LOW_POWER} or {@link ScanSettings#SCAN_TYPE_HIGH_ACCURACY}.
  6. * @param freqs list of frequencies to scan for, if null scan all supported channels.
  7. * @param hiddenNetworkSSIDs List of hidden networks to be scanned for.
  8. * @return Returns true on success.
  9. */
  10. public boolean scan(@NonNull String ifaceName, int scanType, Set<Integer> freqs,
  11. Set<String> hiddenNetworkSSIDs) {
  12. return mWificondControl.scan(ifaceName, scanType, freqs, hiddenNetworkSSIDs);
  13. }

看mWificondControl.scan。

 

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

  1. /**
  2. * Start a scan using wificond for the given parameters.
  3. * @param ifaceName Name of the interface.
  4. * @param scanType Type of scan to perform.
  5. * @param freqs list of frequencies to scan for, if null scan all supported channels.
  6. * @param hiddenNetworkSSIDs List of hidden networks to be scanned for.
  7. * @return Returns true on success.
  8. */
  9. public boolean scan(@NonNull String ifaceName,
  10. int scanType,
  11. Set<Integer> freqs,
  12. Set<String> hiddenNetworkSSIDs) {
  13. IWifiScannerImpl scannerImpl = getScannerImpl(ifaceName);
  14. if (scannerImpl == null) {
  15. Log.e(TAG, "No valid wificond scanner interface handler");
  16. return false;
  17. }
  18. SingleScanSettings settings = new SingleScanSettings();
  19. try {
  20. settings.scanType = getScanType(scanType);
  21. } catch (IllegalArgumentException e) {
  22. Log.e(TAG, "Invalid scan type ", e);
  23. return false;
  24. }
  25. settings.channelSettings = new ArrayList<>();
  26. settings.hiddenNetworks = new ArrayList<>();
  27. if (freqs != null) {
  28. for (Integer freq : freqs) {
  29. ChannelSettings channel = new ChannelSettings();
  30. channel.frequency = freq;
  31. settings.channelSettings.add(channel);
  32. }
  33. }
  34. if (hiddenNetworkSSIDs != null) {
  35. for (String ssid : hiddenNetworkSSIDs) {
  36. HiddenNetwork network = new HiddenNetwork();
  37. try {
  38. network.ssid = NativeUtil.byteArrayFromArrayList(NativeUtil.decodeSsid(ssid));
  39. } catch (IllegalArgumentException e) {
  40. Log.e(TAG, "Illegal argument " + ssid, e);
  41. continue;
  42. }
  43. settings.hiddenNetworks.add(network);
  44. }
  45. }
  46. try {
  47. return scannerImpl.scan(settings);
  48. } catch (RemoteException e1) {
  49. Log.e(TAG, "Failed to request scan due to remote exception");
  50. }
  51. return false;
  52. }

又调到scannerImpl.scan了,看getScannerImpl。

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

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

  1. /**
  2. * Setup interface for client mode via wificond.
  3. * @return An IClientInterface as wificond client interface binder handler.
  4. * Returns null on failure.
  5. */
  6. public IClientInterface setupInterfaceForClientMode(@NonNull String ifaceName) {
  7. Log.d(TAG, "Setting up interface for client mode");
  8. if (!retrieveWificondAndRegisterForDeath()) {
  9. return null;
  10. }
  11. IClientInterface clientInterface = null;
  12. try {
  13. clientInterface = mWificond.createClientInterface(ifaceName);
  14. } catch (RemoteException e1) {
  15. Log.e(TAG, "Failed to get IClientInterface due to remote exception");
  16. return null;
  17. }
  18. if (clientInterface == null) {
  19. Log.e(TAG, "Could not get IClientInterface instance from wificond");
  20. return null;
  21. }
  22. Binder.allowBlocking(clientInterface.asBinder());
  23. // Refresh Handlers
  24. mClientInterfaces.put(ifaceName, clientInterface);
  25. try {
  26. IWifiScannerImpl wificondScanner = clientInterface.getWifiScannerImpl();
  27. if (wificondScanner == null) {
  28. Log.e(TAG, "Failed to get WificondScannerImpl");
  29. return null;
  30. }
  31. mWificondScanners.put(ifaceName, wificondScanner);
  32. Binder.allowBlocking(wificondScanner.asBinder());
  33. ScanEventHandler scanEventHandler = new ScanEventHandler(ifaceName);
  34. mScanEventHandlers.put(ifaceName, scanEventHandler);
  35. wificondScanner.subscribeScanEvents(scanEventHandler);
  36. PnoScanEventHandler pnoScanEventHandler = new PnoScanEventHandler(ifaceName);
  37. mPnoScanEventHandlers.put(ifaceName, pnoScanEventHandler);
  38. wificondScanner.subscribePnoScanEvents(pnoScanEventHandler);
  39. } catch (RemoteException e) {
  40. Log.e(TAG, "Failed to refresh wificond scanner due to remote exception");
  41. }
  42. return clientInterface;
  43. }

看retrieveWificondAndRegisterForDeath。

  1. /**
  2. * Helper method to retrieve the global wificond handle and register for
  3. * death notifications.
  4. */
  5. private boolean retrieveWificondAndRegisterForDeath() {
  6. if (mWificond != null) {
  7. if (mVerboseLoggingEnabled) {
  8. Log.d(TAG, "Wificond handle already retrieved");
  9. }
  10. // We already have a wificond handle.
  11. return true;
  12. }
  13. mWificond = mWifiInjector.makeWificond();
  14. if (mWificond == null) {
  15. Log.e(TAG, "Failed to get reference to wificond");
  16. return false;
  17. }
  18. try {
  19. mWificond.asBinder().linkToDeath(this, 0);
  20. } catch (RemoteException e) {
  21. Log.e(TAG, "Failed to register death notification for wificond");
  22. // The remote has already died.
  23. return false;
  24. }
  25. return true;
  26. }

看mWiifInjector.makeWificond。

 

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

  1. public IWificond makeWificond() {
  2. // We depend on being able to refresh our binder in WifiStateMachine, so don't cache it.
  3. IBinder binder = ServiceManager.getService(WIFICOND_SERVICE_NAME);
  4. return IWificond.Stub.asInterface(binder);
  5. }

再往下走就是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,return,scan,wifi,源码,SCAN,WifiManager,java,Android
来源: https://blog.csdn.net/m0_37905055/article/details/101193598