[转载] Wifi模块—源码分析Wifi热点扫描(Android P)
作者:互联网
一 前言
这次接着讲Wifi工程流程中的Wifi热点查找过程,也是Wifi启动的过程延续,Wifi启动过程中会更新Wifi的状态,框架层也有相应广播发出,应用层接收到广播后开始进行热点的扫描。可以先看前面Wifi启动的分析过程。
二 图示调用流程
由于在 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。
- @Override
- public 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.
- */
- @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);
- }
- }
- };
看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是内部类。
- @VisibleForTesting
- class 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 style="1">
- * <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.
- */
- @Deprecated
- public 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.
- */
- @Override
- public 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。
- @Override
- public 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,return,scan,wifi,源码,SCAN,WifiManager,java,Android 来源: https://blog.csdn.net/m0_37905055/article/details/101193598