首先看WifiServiceImpl的startScan方法:
//packages/modules/Wifi/service/java/com/android/server/wifi/WifiServiceImpl.java
public class WifiServiceImpl extends BaseWifiService {
private final ScanRequestProxy mScanRequestProxy;
private final WifiPermissionsUtil mWifiPermissionsUtil;
public boolean startScan(String packageName, String featureId) {
if (enforceChangePermission(packageName) != MODE_ALLOWED) {
return false;
}
int callingUid = Binder.getCallingUid();
mWifiPermissionsUtil.checkPackage(callingUid, packageName);
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, featureId, callingUid,
null); //用于确定调用方是否有权获取扫描结果的 API。如果调用方没有权限,则引发安全异常。
Boolean scanSuccess = mWifiThreadRunner.call(() ->
mScanRequestProxy.startScan(callingUid, packageName), null); //调用ScanRequestProxy的startScan方法
if (scanSuccess == null) {
sendFailedScanBroadcast();
return false;
}
if (!scanSuccess) {
Log.e(TAG, "Failed to start scan");
return false;
}
} catch (SecurityException e) {
Log.w(TAG, "Permission violation - startScan not allowed for"
+ " uid=" + callingUid + ", packageName=" + packageName + ", reason=" + e);
return false;
} finally {
Binder.restoreCallingIdentity(ident);
}
return true;
}
}
调用ScanRequestProxy的startScan方法:
//packages/modules/Wifi/service/java/com/android/server/wifi/ScanRequestProxy.java
public class ScanRequestProxy {
private WifiScanner mWifiScanner;
public boolean startScan(int callingUid, String packageName) {
if (!mScanningEnabled || !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 unless,
// a) App has either NETWORK_SETTINGS or NETWORK_SETUP_WIZARD permission.
// b) Throttling has been disabled by user.
int packageImportance = getPackageImportance(callingUid, packageName);
if (!fromSettingsOrSetupWizard && mThrottleEnabled
&& shouldScanRequestBeThrottledForApp(callingUid, packageName, packageImportance)) {
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, packageName);
mWifiMetrics.getScanMetrics().setWorkSource(workSource);
mWifiMetrics.getScanMetrics().setImportance(packageImportance);
// 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.SCAN_TYPE_HIGH_ACCURACY;
} else {
if (SdkLevel.isAtLeastS()) {
// since the scan request is from a normal app, do not scan all 6Ghz channels.
settings.set6GhzPscOnlyEnabled(true);
}
}
settings.band = WifiScanner.WIFI_BAND_ALL;
settings.reportEvents = WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN
| WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT;
if (mScanningForHiddenNetworksEnabled) {
settings.hiddenNetworks.clear();
// retrieve the list of hidden network SSIDs from saved network to scan for, if enabled.
settings.hiddenNetworks.addAll(mWifiConfigManager.retrieveHiddenNetworkList(false));
// retrieve the list of hidden network SSIDs from Network suggestion to scan for.
settings.hiddenNetworks.addAll(
mWifiInjector.getWifiNetworkSuggestionsManager()
.retrieveHiddenNetworkList(false));
}
mWifiScanner.startScan(settings, new HandlerExecutor(mHandler),
new ScanRequestProxyScanListener(), workSource); //调用WifiScanner的startScan方法,new一个监听器并作为参数传递,以便HAL层返回扫描结果
return true;
}
}
调用WifiScanner的startScan方法:
//packages/modules/Wifi/framework/java/android/net/wifi/WifiScanner.java
public class WifiScanner {
@RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
public void startScan(ScanSettings settings, @Nullable @CallbackExecutor Executor executor,
ScanListener listener, WorkSource workSource) {
Objects.requireNonNull(listener, "listener cannot be null");
int key = addListener(listener, executor); //将侦听器添加到侦听器map中
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);
scanParams.putString(REQUEST_PACKAGE_NAME_KEY, mContext.getOpPackageName());
scanParams.putString(REQUEST_FEATURE_ID_KEY, mContext.getAttributionTag());
mAsyncChannel.sendMessage(CMD_START_SINGLE_SCAN, 0, key, scanParams); //发送CMD_START_SINGLE_SCAN消息
}
}
发送的消息由WifiScanningServiceImpl内部类ClientHandler的handleMessage方法处理:
//packages/modules/Wifi/framework/java/android/net/wifi/scanner/WifiScanningServiceImpl.java
public class WifiScanningServiceImpl extends IWifiScanner.Stub {
private WifiSingleScanStateMachine mSingleScanStateMachine;
private class ClientHandler extends Handler {
ClientHandler(String tag, Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION: {
if (msg.replyTo == null) {
logw("msg.replyTo is null");
return;
}
ExternalClientInfo client = (ExternalClientInfo) mClients.get(msg.replyTo);
if (client != null) {
logw("duplicate client connection: " + msg.sendingUid + ", messenger="
+ msg.replyTo);
client.mChannel.replyToMessage(msg, AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED,
AsyncChannel.STATUS_FULL_CONNECTION_REFUSED_ALREADY_CONNECTED);
return;
}
AsyncChannel ac = new AsyncChannel();
ac.connected(mContext, this, msg.replyTo);
client = new ExternalClientInfo(msg.sendingUid, msg.replyTo, ac);
client.register();
ac.replyToMessage(msg, AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED,
AsyncChannel.STATUS_SUCCESSFUL);
localLog("client connected: " + client);
return;
}
case AsyncChannel.CMD_CHANNEL_DISCONNECT: {
ExternalClientInfo client = (ExternalClientInfo) mClients.get(msg.replyTo);
if (client != null) {
client.mChannel.disconnect();
}
return;
}
case AsyncChannel.CMD_CHANNEL_DISCONNECTED: {
ExternalClientInfo client = (ExternalClientInfo) mClients.get(msg.replyTo);
if (client != null && msg.arg1 != AsyncChannel.STATUS_SEND_UNSUCCESSFUL
&& msg.arg1
!= AsyncChannel.STATUS_FULL_CONNECTION_REFUSED_ALREADY_CONNECTED) {
localLog("client disconnected: " + client + ", reason: " + msg.arg1);
client.cleanup();
}
return;
}
}
try {
enforcePermission(msg.sendingUid, msg);
} catch (SecurityException e) {
localLog("failed to authorize app: " + e);
replyFailed(msg, WifiScanner.REASON_NOT_AUTHORIZED, "Not authorized");
return;
}
// Since the CMD_GET_SCAN_RESULTS and CMD_GET_SINGLE_SCAN_RESULTS messages are
// sent from WifiScanner using |sendMessageSynchronously|, handle separately since
// the |msg.replyTo| field does not actually correspond to the Messenger that is
// registered for that client.
if (msg.what == WifiScanner.CMD_GET_SCAN_RESULTS) {
mBackgroundScanStateMachine.sendMessage(Message.obtain(msg));
return;
}
if (msg.what == WifiScanner.CMD_GET_SINGLE_SCAN_RESULTS) {
mSingleScanStateMachine.sendMessage(Message.obtain(msg));
return;
}
ClientInfo ci = mClients.get(msg.replyTo);
if (ci == null) {
loge("Could not find client info for message " + msg.replyTo + ", msg=" + msg);
replyFailed(msg, WifiScanner.REASON_INVALID_LISTENER, "Could not find listener");
return;
}
switch (msg.what) {
case WifiScanner.CMD_ENABLE:
Log.i(TAG, "Received a request to enable scanning, UID = " + msg.sendingUid);
setupScannerImpls();
mBackgroundScanStateMachine.sendMessage(Message.obtain(msg));
mSingleScanStateMachine.sendMessage(Message.obtain(msg));
mPnoScanStateMachine.sendMessage(Message.obtain(msg));
mLastCallerInfoManager.put(WifiManager.API_SCANNING_ENABLED, msg.arg1,
msg.sendingUid, msg.arg2, (String) msg.obj, true);
break;
case WifiScanner.CMD_DISABLE:
Log.i(TAG, "Received a request to disable scanning, UID = " + msg.sendingUid);
teardownScannerImpls();
mBackgroundScanStateMachine.sendMessage(Message.obtain(msg));
mSingleScanStateMachine.sendMessage(Message.obtain(msg));
mPnoScanStateMachine.sendMessage(Message.obtain(msg));
mLastCallerInfoManager.put(WifiManager.API_SCANNING_ENABLED, msg.arg1,
msg.sendingUid, msg.arg2, (String) msg.obj, false);
break;
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)); //调用WifiSingleScanStateMachine的sendMessage方法发送CMD_START_SINGLE_SCAN消息
break;
case WifiScanner.CMD_REGISTER_SCAN_LISTENER:
logScanRequest("registerScanListener", ci, msg.arg2, null, null, null);
mSingleScanListeners.addRequest(ci, msg.arg2, null, null);
replySucceeded(msg);
break;
case WifiScanner.CMD_DEREGISTER_SCAN_LISTENER:
logScanRequest("deregisterScanListener", ci, msg.arg2, null, null, null);
mSingleScanListeners.removeRequest(ci, msg.arg2);
break;
default:
replyFailed(msg, WifiScanner.REASON_INVALID_REQUEST, "Invalid request");
break;
}
}
}
}
发给内部状态机WifiSingleScanStateMachine进行处理:
//packages/modules/Wifi/framework/java/android/net/wifi/scanner/WifiScanningServiceImpl.java
public class WifiScanningServiceImpl extends IWifiScanner.Stub {
class WifiSingleScanStateMachine extends StateMachine {
class DefaultState extends State {
@Override
public void enter() {
mActiveScans.clear();
mPendingScans.clear();
}
@Override
public boolean processMessage(Message msg) {
ClientInfo ci = mClients.get(msg.replyTo);
switch (msg.what) {
case WifiScanner.CMD_ENABLE:
if (mScannerImpls.isEmpty()) {
loge("Failed to start single scan state machine because scanner impl"
+ " is null");
return HANDLED;
}
transitionTo(mIdleState);
return HANDLED;
case WifiScanner.CMD_DISABLE:
transitionTo(mDefaultState);
return HANDLED;
case WifiScanner.CMD_START_SINGLE_SCAN:
handleScanStartMessage(ci, msg);
return HANDLED;
case WifiScanner.CMD_STOP_SINGLE_SCAN:
removeSingleScanRequest(ci, msg.arg2);
return HANDLED;
case CMD_SCAN_RESULTS_AVAILABLE:
if (DBG) localLog("ignored scan results available event");
return HANDLED;
case CMD_FULL_SCAN_RESULTS:
if (DBG) localLog("ignored full scan result event");
return HANDLED;
case WifiScanner.CMD_GET_SINGLE_SCAN_RESULTS:
msg.obj = new WifiScanner.ParcelableScanResults(
filterCachedScanResultsByAge());
replySucceeded(msg);
return HANDLED;
default:
return NOT_HANDLED;
}
}
/**
* Filter out any scan results that are older than
* {@link #CACHED_SCAN_RESULTS_MAX_AGE_IN_MILLIS}.
*
* @return Filtered list of scan results.
*/
private ScanResult[] filterCachedScanResultsByAge() {
// Using ScanResult.timestamp here to ensure that we use the same fields as
// WificondScannerImpl for filtering stale results.
long currentTimeInMillis = mClock.getElapsedSinceBootMillis();
return mCachedScanResults.stream()
.filter(scanResult
-> ((currentTimeInMillis - (scanResult.timestamp / 1000))
< CACHED_SCAN_RESULTS_MAX_AGE_IN_MILLIS))
.toArray(ScanResult[]::new);
}
}
}
}
由状态机WifiSingleScanStateMachine的handleScanStartMessage方法处理:
//packages/modules/Wifi/framework/java/android/net/wifi/scanner/WifiScanningServiceImpl.java
public class WifiScanningServiceImpl extends IWifiScanner.Stub {
class WifiSingleScanStateMachine extends StateMachine {
private void handleScanStartMessage(ClientInfo ci, Message msg) {
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;
}
ScanSettings scanSettings = null;
WorkSource workSource = null;
try {
scanSettings =
scanParams.getParcelable(
WifiScanner.SCAN_PARAMS_SCAN_SETTINGS_KEY);
workSource =
scanParams.getParcelable(
WifiScanner.SCAN_PARAMS_WORK_SOURCE_KEY);
} catch (BadParcelableException e) {
Log.wtf(TAG, "Failed to get parcelable params", e);
logCallback("singleScanInvalidRequest", ci, handler,
"bad parcel params");
replyFailed(msg, WifiScanner.REASON_INVALID_REQUEST,
"bad parcel params");
return;
}
if (validateScanRequest(ci, handler, scanSettings)) {
if (getCurrentState() == mDefaultState && !scanSettings.ignoreLocationSettings) {
// Reject regular scan requests if scanning is disabled.
replyFailed(msg, WifiScanner.REASON_UNSPECIFIED, "not available");
return;
}
mWifiMetrics.incrementOneshotScanCount();
if ((scanSettings.band & WifiScanner.WIFI_BAND_5_GHZ_DFS_ONLY) != 0) {
mWifiMetrics.incrementOneshotScanWithDfsCount();
}
logScanRequest("addSingleScanRequest", ci, handler, workSource,
scanSettings, null);
replySucceeded(msg);
if (scanSettings.ignoreLocationSettings) {
// Inform wifi manager that an emergency scan is in progress (regardless of
// whether scanning is currently enabled or not). This ensures that
// the wifi chip remains on for the duration of this scan.
mWifiManager.setEmergencyScanRequestInProgress(true);
}
if (getCurrentState() == mScanningState) {
// 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 (activeScanSatisfies(scanSettings)) {
mActiveScans.addRequest(ci, handler, workSource, scanSettings);
} else {
mPendingScans.addRequest(ci, handler, workSource, scanSettings);
}
} else if (getCurrentState() == mIdleState) {
// 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.
mPendingScans.addRequest(ci, handler, workSource, scanSettings);
tryToStartNewScan(); //如果是Idle状态,调用tryToStartNewScan方法
} else if (getCurrentState() == mDefaultState) {
// If scanning is disabled and the request is for emergency purposes
// (checked above), add to pending list. this scan will be scheduled when
// transitioning to IdleState when wifi manager enables scanning as a part of
// processing WifiManager.setEmergencyScanRequestInProgress(true)
mPendingScans.addRequest(ci, handler, workSource, scanSettings);
}
} else {
logCallback("singleScanInvalidRequest", ci, handler, "bad request");
replyFailed(msg, WifiScanner.REASON_INVALID_REQUEST, "bad request");
mWifiMetrics.incrementScanReturnEntry(
WifiMetricsProto.WifiLog.SCAN_FAILURE_INVALID_CONFIGURATION, 1);
}
}
}
}
如果是Idle状态,调用tryToStartNewScan方法:
//packages/modules/Wifi/framework/java/android/net/wifi/scanner/WifiScanningServiceImpl.java
public class WifiScanningServiceImpl extends IWifiScanner.Stub {
class WifiSingleScanStateMachine extends StateMachine {
private final ScannerImplsTracker mScannerImplsTracker;
void tryToStartNewScan() {
if (mPendingScans.size() == 0) { // no pending requests
return;
}
mChannelHelper.updateChannels();
// TODO move merging logic to a scheduler
WifiNative.ScanSettings settings = new WifiNative.ScanSettings();
settings.num_buckets = 1;
WifiNative.BucketSettings bucketSettings = new WifiNative.BucketSettings();
bucketSettings.bucket = 0;
bucketSettings.period_ms = 0;
bucketSettings.report_events = WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN;
ChannelCollection channels = mChannelHelper.createChannelCollection();
WifiScanner.ChannelSpec[][] available6GhzChannels =
mChannelHelper.getAvailableScanChannels(WifiScanner.WIFI_BAND_6_GHZ);
boolean are6GhzChannelsAvailable = available6GhzChannels.length > 0
&& available6GhzChannels[0].length > 0;
List<WifiNative.HiddenNetwork> hiddenNetworkList = new ArrayList<>();
for (RequestInfo<ScanSettings> entry : mPendingScans) {
settings.scanType = mergeScanTypes(settings.scanType, entry.settings.type);
if (are6GhzChannelsAvailable) {
settings.enable6GhzRnr = mergeRnrSetting(
settings.enable6GhzRnr, entry.settings);
} else {
settings.enable6GhzRnr = false;
}
channels.addChannels(entry.settings);
for (ScanSettings.HiddenNetwork srcNetwork : entry.settings.hiddenNetworks) {
WifiNative.HiddenNetwork hiddenNetwork = new WifiNative.HiddenNetwork();
hiddenNetwork.ssid = srcNetwork.ssid;
hiddenNetworkList.add(hiddenNetwork);
}
if ((entry.settings.reportEvents & WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT)
!= 0) {
bucketSettings.report_events |= WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT;
}
if (entry.clientInfo != null) {
mWifiMetrics.getScanMetrics().setClientUid(entry.clientInfo.mUid);
}
mWifiMetrics.getScanMetrics().setWorkSource(entry.workSource);
}
if (hiddenNetworkList.size() > 0) {
settings.hiddenNetworks = new WifiNative.HiddenNetwork[hiddenNetworkList.size()];
int numHiddenNetworks = 0;
for (WifiNative.HiddenNetwork hiddenNetwork : hiddenNetworkList) {
settings.hiddenNetworks[numHiddenNetworks++] = hiddenNetwork;
}
}
channels.fillBucketSettings(bucketSettings, Integer.MAX_VALUE);
settings.buckets = new WifiNative.BucketSettings[] {bucketSettings};
if (mScannerImplsTracker.startSingleScan(settings)) {
mWifiMetrics.getScanMetrics().logScanStarted(
WifiMetrics.ScanMetrics.SCAN_TYPE_SINGLE);
// 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());
mWifiMetrics.getScanMetrics().logScanFailedToStart(
WifiMetrics.ScanMetrics.SCAN_TYPE_SINGLE);
// notify and cancel failed scans
sendOpFailedToAllAndClear(mPendingScans, WifiScanner.REASON_UNSPECIFIED,
"Failed to start single scan");
}
}
}
调用ScannerImplsTracker的startSingleScan方法:
//packages/modules/Wifi/framework/java/android/net/wifi/scanner/WifiScanningServiceImpl.java
public class WifiScanningServiceImpl extends IWifiScanner.Stub {
class WifiSingleScanStateMachine extends StateMachine {
private final class ScannerImplsTracker {
public boolean startSingleScan(WifiNative.ScanSettings scanSettings) {
mStatusPerImpl.clear();
boolean anySuccess = false;
for (Map.Entry<String, WifiScannerImpl> entry : mScannerImpls.entrySet()) {
String ifaceName = entry.getKey();
WifiScannerImpl impl = entry.getValue();
boolean success = impl.startSingleScan(
scanSettings, new ScanEventHandler(ifaceName)); //调用WifiScannerImpl的startSingleScan方法
if (!success) {
Log.e(TAG, "Failed to start single scan on " + ifaceName);
mStatusPerImpl.put(ifaceName, STATUS_FAILED);
continue;
}
mStatusPerImpl.put(ifaceName, STATUS_PENDING);
anySuccess = true;
}
return anySuccess;
}
}
}
}
调用WifiScannerImpl的startSingleScan方法,WifiScannerImpl是一个抽象类,其具体实现为HalWifiScannerImpl,因此会调用HalWifiScannerImpl的startSingleScan方法:
//packages/modules/Wifi/framework/java/android/net/wifi/scanner/HalWifiScannerImpl.java
/**
* WifiScanner implementation that takes advantage of the gscan HAL API
* The gscan API is used to perform background scans and wificond is used for oneshot scans.
* @see com.android.server.wifi.scanner.WifiScannerImpl for more details on each method.
*/
public class HalWifiScannerImpl extends WifiScannerImpl implements Handler.Callback {
private final WificondScannerImpl mWificondScannerDelegate;
public boolean startSingleScan(WifiNative.ScanSettings settings,
WifiNative.ScanEventHandler eventHandler) {
return mWificondScannerDelegate.startSingleScan(settings, eventHandler);
}
}
调用WificondScannerImpl的startSingleScan方法:
//packages/modules/Wifi/framework/java/android/net/wifi/scanner/WificondScannerImpl.java
/**
* Implementation of the WifiScanner HAL API that uses wificond to perform all scans
* @see com.android.server.wifi.scanner.WifiScannerImpl for more details on each method.
*/
public class WificondScannerImpl extends WifiScannerImpl implements Handler.Callback {
private final WifiNative mWifiNative;
public boolean startSingleScan(WifiNative.ScanSettings settings,
WifiNative.ScanEventHandler eventHandler) {
if (eventHandler == null || settings == null) {
Log.w(TAG, "Invalid arguments for startSingleScan: settings=" + settings
+ ",eventHandler=" + eventHandler);
return false;
}
synchronized (mSettingsLock) {
if (mLastScanSettings != null) {
Log.w(TAG, "A single scan is already running");
return false;
}
ChannelCollection allFreqs = mChannelHelper.createChannelCollection();
boolean reportFullResults = false;
for (int i = 0; i < settings.num_buckets; ++i) {
WifiNative.BucketSettings bucketSettings = settings.buckets[i];
if ((bucketSettings.report_events
& WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT) != 0) {
reportFullResults = true;
}
allFreqs.addChannels(bucketSettings);
}
List<String> hiddenNetworkSSIDSet = new ArrayList<>();
if (settings.hiddenNetworks != null) {
boolean executeRoundRobin = true;
int maxNumScanSsids = mMaxNumScanSsids;
if (maxNumScanSsids <= 0) {
// Subtract 1 to account for the wildcard/broadcast probe request that
// wificond adds to the scan set.
mMaxNumScanSsids = mWifiNative.getMaxSsidsPerScan(getIfaceName()) - 1;
if (mMaxNumScanSsids > 0) {
maxNumScanSsids = mMaxNumScanSsids;
} else {
maxNumScanSsids = DEFAULT_NUM_HIDDEN_NETWORK_IDS_PER_SCAN;
executeRoundRobin = false;
}
}
int numHiddenNetworksPerScan =
Math.min(settings.hiddenNetworks.length, maxNumScanSsids);
if (numHiddenNetworksPerScan == settings.hiddenNetworks.length
|| mNextHiddenNetworkScanId >= settings.hiddenNetworks.length
|| !executeRoundRobin) {
mNextHiddenNetworkScanId = 0;
}
if (DBG) {
Log.d(TAG, "Scanning for " + numHiddenNetworksPerScan + " out of "
+ settings.hiddenNetworks.length + " total hidden networks");
Log.d(TAG, "Scan hidden networks starting at id=" + mNextHiddenNetworkScanId);
}
int id = mNextHiddenNetworkScanId;
for (int i = 0; i < numHiddenNetworksPerScan; i++, id++) {
hiddenNetworkSSIDSet.add(
settings.hiddenNetworks[id % settings.hiddenNetworks.length].ssid);
}
mNextHiddenNetworkScanId = id % settings.hiddenNetworks.length;
}
mLastScanSettings = new LastScanSettings(
mClock.getElapsedSinceBootNanos(),
reportFullResults, allFreqs, eventHandler);
boolean success = false;
Set<Integer> freqs = Collections.emptySet();
if (!allFreqs.isEmpty()) {
freqs = allFreqs.getScanFreqs();
success = mWifiNative.scan(
getIfaceName(), settings.scanType, freqs, hiddenNetworkSSIDSet,
settings.enable6GhzRnr); //调用WifiNative的scan方法
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
+ " on iface " + getIfaceName());
}
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(() -> reportScanFailure());
}
return true;
}
}
}
调用WifiNative的scan方法:
//packages/modules/Wifi/service/java/com/android/server/wifi/WifiNative.java
/**
* Native calls for bring up/shut down of the supplicant daemon and for
* sending requests to the supplicant daemon
*
* {@hide}
*/
public class WifiNative {
private final WifiNl80211Manager mWifiCondManager;
public boolean scan(
@NonNull String ifaceName, @WifiAnnotations.ScanType int scanType, Set<Integer> freqs,
List<String> hiddenNetworkSSIDs, boolean enable6GhzRnr) {
List<byte[]> hiddenNetworkSsidsArrays = new ArrayList<>();
for (String hiddenNetworkSsid : hiddenNetworkSSIDs) {
try {
hiddenNetworkSsidsArrays.add(
NativeUtil.byteArrayFromArrayList(
NativeUtil.decodeSsid(hiddenNetworkSsid)));
} catch (IllegalArgumentException e) {
Log.e(TAG, "Illegal argument " + hiddenNetworkSsid, e);
continue;
}
}
// enable6GhzRnr is a new parameter first introduced in Android S.
if (SdkLevel.isAtLeastS()) {
Bundle extraScanningParams = new Bundle();
extraScanningParams.putBoolean(WifiNl80211Manager.SCANNING_PARAM_ENABLE_6GHZ_RNR,
enable6GhzRnr);
return mWifiCondManager.startScan(ifaceName, scanType, freqs, hiddenNetworkSsidsArrays,
extraScanningParams); //调用WifiCondManager的startScan方法
} else {
return mWifiCondManager.startScan(ifaceName, scanType, freqs, hiddenNetworkSsidsArrays); //调用WifiCondManager的startScan方法
}
}
}
调用WifiNl80211Manager的startScan方法:
//frameworks/base/wifi/java/src/android/net/wifi/nl80211/WifiNl80211Manager.java
public class WifiNl80211Manager {
//使用指定的参数启动扫描。扫描是一种异步操作。操作结果在使用 设置接口时注册的 {@link 扫描事件回调} 中返回
public boolean startScan(@NonNull String ifaceName, @WifiAnnotations.ScanType int scanType,
@SuppressLint("NullableCollection") @Nullable Set<Integer> freqs,
@SuppressLint("NullableCollection") @Nullable List<byte[]> hiddenNetworkSSIDs,
@SuppressLint("NullableCollection") @Nullable Bundle extraScanningParams) {
IWifiScannerImpl scannerImpl = getScannerImpl(ifaceName);
if (scannerImpl == null) {
Log.e(TAG, "No valid wificond scanner interface handler for iface=" + ifaceName);
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 (extraScanningParams != null) {
settings.enable6GhzRnr = extraScanningParams.getBoolean(SCANNING_PARAM_ENABLE_6GHZ_RNR);
}
if (freqs != null) {
for (Integer freq : freqs) {
ChannelSettings channel = new ChannelSettings();
channel.frequency = freq;
settings.channelSettings.add(channel);
}
}
if (hiddenNetworkSSIDs != null) {
for (byte[] ssid : hiddenNetworkSSIDs) {
HiddenNetwork network = new HiddenNetwork();
network.ssid = ssid;
// settings.hiddenNetworks is expected to be very small, so this shouldn't cause
// any performance issues.
if (!settings.hiddenNetworks.contains(network)) {
settings.hiddenNetworks.add(network);
}
}
}
try {
return scannerImpl.scan(settings); //调用IWifiScannerImpl的scan方法
} catch (RemoteException e1) {
Log.e(TAG, "Failed to request scan due to remote exception");
}
return false;
}
}
调用IWifiScannerImpl的scan方法,IWifiScannerImpl是一个AIDL接口,由wificond的ScannerImp类实现,之后就是HAL层的处理了,这里就不再介绍了。