版权声明:本文为博主原创文章,未经博主允许不得转载。
在之前的分析中WIFI已经启动了,wpa_supplicant enabled,下面我们开始来分析wifi启动后是如何来扫描周围的AP的?
在Android O之前,wifi的扫描是通过frameworks层发命令到wifinative,再到hardware/libhardware_legacy/wifi/wifi.c,然后调用wpa_supplicant API,将scan的命令通过wpa_supplicant下发到kernel,但是在Android O中scan跟以前版本不同了
1.Android O的scan跟之前Android版本存在的差异
1) Android O开始scan的命令不是通过wpa_supplicant下发到kernel,而是直接由wificond传送到kernel,而scan results的结果也是直接由kernel传给wificond,再由wificond传送给上层去显示
2) 在framework层,现在scan改由scanner这个类去使用,之前从6.0开始慢慢用起来,现在到了8.0,可以说已经用了近95%了,剩下了目前google还在修改中,google的目标应该是想把scan整个完全独立出来,不跟其他的扯太大,例如WifiStateMachine
3) 目前上层下发的scan,已经改由SettingsLib去定时下,不交给apk去做了。
在android 8.0之前的版本,scan的定时扫描都是在上层app做的,但从8.0开始,google把这个定时器改到了framework中的SettingsLib(frameworks/base/packages/SettingsLib)中去了
4) 之前的版本scan操作,当同一时间下两次scan时,是直接交由wpa_supplicant去隔开的,现在由于直接把scan下发给kernel。所以,google已经把上层下的scan跟framework的自动scan也实现了分离,不让这两种flow打到,让同一时间只下一次scan,后一次则做pending动作
2. 流程分析
2.1 Settings
WiFi Settings在Android 8.0代码同样分为两部分,packages/apps/Settings和framework/base/packages/SettingsLib。
/packages/apps/Settings/src/com/android/settings/wifi/WifiSettings.java
@Override
public void onStart() {
super.onStart();
// On/off switch is hidden for Setup Wizard (returns null)
mWifiEnabler = createWifiEnabler();
mWifiTracker.startTracking();
if (mIsRestricted) {
restrictUi();
return;
}
onWifiStateChanged(mWifiManager.getWifiState());
}
这里会调用到SettingsLib的WifiTracker,WifiTracker中包含了wifi扫描的操作。比较奇怪的是,这里没有走监听wifi打开消息,待WiFi打开后开始扫描,而是只要在WiFi界面就开始扫描了。不用奇怪,因为后面会去做检查只有wifi打开之后,才会真正下发scan命令到底层,具体请看下面的分析。
2.2 SettingsLib
/frameworks/base/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
/**
* Start tracking wifi networks and scores.
*
* <p>Registers listeners and starts scanning for wifi networks. If this is not called
* then forceUpdate() must be called to populate getAccessPoints().
*/
@MainThread
public void startTracking() {
synchronized (mLock) {
registerScoreCache();
mNetworkScoringUiEnabled =
Settings.Global.getInt(
mContext.getContentResolver(),
Settings.Global.NETWORK_SCORING_UI_ENABLED, 0) == 1;
mMaxSpeedLabelScoreCacheAge =
Settings.Global.getLong(
mContext.getContentResolver(),
Settings.Global.SPEED_LABEL_CACHE_EVICTION_AGE_MILLIS,
DEFAULT_MAX_CACHED_SCORE_AGE_MILLIS);
resumeScanning();
if (!mRegistered) {
mContext.registerReceiver(mReceiver, mFilter);
// NetworkCallback objects cannot be reused. http://b/20701525 .
mNetworkCallback = new WifiTrackerNetworkCallback();
mConnectivityManager.registerNetworkCallback(mNetworkRequest, mNetworkCallback);
mRegistered = true;
}
}
}
startTracking() –> resumeScanning();
/**
* Resume scanning for wifi networks after it has been paused.
*
* <p>The score cache should be registered before this method is invoked.
*/
public void resumeScanning() {
if (mScanner == null) {
mScanner = new Scanner();
}
mWorkHandler.sendEmptyMessage(WorkHandler.MSG_RESUME);
if (mWifiManager.isWifiEnabled()) {
mScanner.resume();
}
}
这里可以看到resumeScanning()会去判断wifi有没有打开mWifiManager.isWifiEnabled(),如果没有打开就不继续进行扫描流程了。只有打开了wifi才会调用mScanner.resume()继续走下去
frameworks/base/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
@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 forceScan() {
removeMessages(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);
}
}
class Scanner是WifiTracker中的一个内部类,整个类就这么一点代码,那么来分析一下这个Scanner类,前面调用的这个mScanner.resume()函数中就发送了一条消息sendEmptyMessage(MSG_SCAN);然后在类中的handleMessage中对这个消息进行处理,这个类的handleMessage中也只处理这一个消息,从handleMessage函数中可以看到if (message.what != MSG_SCAN) return;如果不是MSG_SCAN就退出函数了,如果是才会接着去进行扫描。
这里可以看到如果扫描失败3次就会导致扫描失败的toast的提醒,如果扫描成功则会进行扫描间隔为10s的持续扫描。
// TODO: Allow control of this?
// Combo scans can take 5-6s to complete - set to 10s.
private static final int WIFI_RESCAN_INTERVAL_MS = 10 * 1000;
从mWifiManager.startScan()可以知道,这里扫描流程就走到WifiManager里去了
2.3 WiFi framework
2.3.1 WifiManager
/framework/base/wifi/java/android/net/wifi/WifiManager.java
/**
* Request a scan for access points. Returns immediately. The availability
* of the results is made known later by means of an asynchronous event sent
* on completion of the scan.
* @return {@code true} if the operation succeeded, i.e., the scan was initiated
*/
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();
mService.startScan(null, workSource, packageName);
return true;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
从代码角度来看startScan要么返回true要么抛异常呀,false不可能。。。
之前分析过mService对应的服务端是WifiServiceImpl
2.3.2 WifiServiceImpl
framework/opt/net/wifi/service/java/com/android/server/wifi/WifiServiceImpl.java
/**
* see {@link android.net.wifi.WifiManager#startScan}
* and {@link android.net.wifi.WifiManager#startCustomizedScan}
*
* @param settings If null, use default parameter, i.e. full scan.
* @param workSource If null, all blame is given to the calling uid.
* @param packageName Package name of the app that requests wifi scan.
*/
@Override
public void startScan(ScanSettings settings, WorkSource workSource, String packageName) {
enforceChangePermission();
mLog.info("startScan uid=%").c(Binder.getCallingUid()).flush();
// Check and throttle background apps for wifi scan.
if (isRequestFromBackground(packageName)) {
long lastScanMs = mLastScanTimestamps.getOrDefault(packageName, 0L);
long elapsedRealtime = mClock.getElapsedSinceBootMillis();
if (lastScanMs != 0 && (elapsedRealtime - lastScanMs) < mBackgroundThrottleInterval) {
sendFailedScanBroadcast();
return;
}
// Proceed with the scan request and record the time.
mLastScanTimestamps.put(packageName, elapsedRealtime);
}
synchronized (this) {
if (mWifiScanner == null) {
mWifiScanner = mWifiInjector.getWifiScanner();
}
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;
}
}
if (settings != null) {
settings = new ScanSettings(settings);
if (!settings.isValid()) {
Slog.e(TAG, "invalid scan setting");
return;
}
}
if (workSource != null) {
enforceWorkSourcePermission();
// WifiManager currently doesn't use names, so need to clear names out of the
// supplied WorkSource to allow future WorkSource combining.
workSource.clearNames();
}
if (workSource == null && Binder.getCallingUid() >= 0) {
workSource = new WorkSource(Binder.getCallingUid());
}
mWifiStateMachine.startScan(Binder.getCallingUid(), scanRequestCounter++,
settings, workSource);
}
注意这个方法前两个参数传进来的都是null,这边一开始会对wifi扫描的请求对象做个过滤,毕竟WiFi扫描是耗电的,不能谁都来请求一下。不在白名单的后台应用的请求扫描时间间隔如果短于30min,则通报批评。下面是startScan函数中对此过滤的操作和分析
// Check and throttle background apps for wifi scan.
if (isRequestFromBackground(packageName)) {
long lastScanMs = mLastScanTimestamps.getOrDefault(packageName, 0L);
long elapsedRealtime = mClock.getElapsedSinceBootMillis();
if (lastScanMs != 0 && (elapsedRealtime - lastScanMs) < mBackgroundThrottleInterval) {
sendFailedScanBroadcast();
return;
}
// Proceed with the scan request and record the time.
mLastScanTimestamps.put(packageName, elapsedRealtime);
}
isRequestFromBackground函数源码如下:
// Check if the request comes from background.
private boolean isRequestFromBackground(String packageName) {
// Requests from system or wifi are not background.
if (Binder.getCallingUid() == Process.SYSTEM_UID
|| Binder.getCallingUid() == Process.WIFI_UID) {
return false;
}
mAppOps.checkPackage(Binder.getCallingUid(), packageName);
if (mBackgroundThrottlePackageWhitelist.contains(packageName)) {
return false;
}
// getPackageImportance requires PACKAGE_USAGE_STATS permission, so clearing the incoming
// identify so the permission check can be done on system process where wifi runs in.
long callingIdentity = Binder.clearCallingIdentity();
try {
return mActivityManager.getPackageImportance(packageName)
> BACKGROUND_IMPORTANCE_CUTOFF;
} finally {
Binder.restoreCallingIdentity(callingIdentity);
}
}
扫描间隔DEFAULT_SCAN_BACKGROUND_THROTTLE_INTERVAL_MS定义如下
private static final long DEFAULT_SCAN_BACKGROUND_THROTTLE_INTERVAL_MS = 30 * 60 * 1000;
sendFailedScanBroadcast函数源码如下
// Send a failed scan broadcast to indicate the current scan request failed.
private void sendFailedScanBroadcast() {
// clear calling identity to send broadcast
long callingIdentity = Binder.clearCallingIdentity();
try {
Intent intent = new Intent(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
intent.putExtra(WifiManager.EXTRA_RESULTS_UPDATED, false);
mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
} finally {
// restore calling identity
Binder.restoreCallingIdentity(callingIdentity);
}
}
回到刚才的startScan函数。由于传入的前两个参数是null,则直接走到WifiStateMachine里去了。
mWifiStateMachine.startScan(Binder.getCallingUid(), scanRequestCounter++,
settings, workSource);
2.3.3 WifiStateMachine
framework/opt/net/wifi/service/java/com/android/server/wifi/WifiStateMachine.java
/**
* Initiate a wifi scan. If workSource is not null, blame is given to it, otherwise blame is
* given to callingUid.
*
* @param callingUid The uid initiating the wifi scan. Blame will be given here unless
* workSource is specified.
* @param workSource If not null, blame is given to workSource.
* @param settings Scan settings, see {@link ScanSettings}.
*/
public void startScan(int callingUid, int scanCounter,
ScanSettings settings, WorkSource workSource) {
Bundle bundle = new Bundle();
bundle.putParcelable(CUSTOMIZED_SCAN_SETTING, settings);
bundle.putParcelable(CUSTOMIZED_SCAN_WORKSOURCE, workSource);
bundle.putLong(SCAN_REQUEST_TIME, mClock.getWallClockMillis());
sendMessage(CMD_START_SCAN, callingUid, scanCounter, bundle);
}
sendMessage(CMD_START_SCAN, callingUid, scanCounter, bundle);发送一条消息CMD_START_SCAN;
由于前面已经enable supplicant,所以到目前扫描阶段,WifiStateMachine状态机目前的状态应该是SupplicantStartedState,下面来看看WifiStateMachine在SupplicantStartedState 怎么处理这个消息
class SupplicantStartedState extends State {
...
@Override
public boolean processMessage(Message message) {
logStateAndMessage(message, this);
switch(message.what) {
...
case CMD_START_SCAN:
// TODO: remove scan request path (b/31445200)
handleScanRequest(message);
break;
调用handleScanRequest(message);进行处理
private void handleScanRequest(Message message) {
ScanSettings settings = null;
WorkSource workSource = null;
// unbundle parameters
Bundle bundle = (Bundle) message.obj;
if (bundle != null) {
settings = bundle.getParcelable(CUSTOMIZED_SCAN_SETTING);
workSource = bundle.getParcelable(CUSTOMIZED_SCAN_WORKSOURCE);
}
Set<Integer> freqs = null;
if (settings != null && settings.channelSet != null) {
freqs = new HashSet<>();
for (WifiChannel channel : settings.channelSet) {
freqs.add(channel.freqMHz);
}
}
// Retrieve the list of hidden network SSIDs to scan for.
List<WifiScanner.ScanSettings.HiddenNetwork> hiddenNetworks =
mWifiConfigManager.retrieveHiddenNetworkList();
// call wifi native to start the scan
if (startScanNative(freqs, hiddenNetworks, workSource)) {
// a full scan covers everything, clearing scan request buffer
if (freqs == null)
mBufferedScanMsg.clear();
messageHandlingStatus = MESSAGE_HANDLING_STATUS_OK;
return;
}
// if reach here, scan request is rejected
if (!mIsScanOngoing) {
// if rejection is NOT due to ongoing scan (e.g. bad scan parameters),
// discard this request and pop up the next one
if (mBufferedScanMsg.size() > 0) {
sendMessage(mBufferedScanMsg.remove());
}
messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD;
} else if (!mIsFullScanOngoing) {
// if rejection is due to an ongoing scan, and the ongoing one is NOT a full scan,
// buffer the scan request to make sure specified channels will be scanned eventually
if (freqs == null)
mBufferedScanMsg.clear();
if (mBufferedScanMsg.size() < SCAN_REQUEST_BUFFER_MAX_SIZE) {
Message msg = obtainMessage(CMD_START_SCAN,
message.arg1, message.arg2, bundle);
mBufferedScanMsg.add(msg);
} else {
// if too many requests in buffer, combine them into a single full scan
bundle = new Bundle();
bundle.putParcelable(CUSTOMIZED_SCAN_SETTING, null);
bundle.putParcelable(CUSTOMIZED_SCAN_WORKSOURCE, workSource);
Message msg = obtainMessage(CMD_START_SCAN, message.arg1, message.arg2, bundle);
mBufferedScanMsg.clear();
mBufferedScanMsg.add(msg);
}
messageHandlingStatus = MESSAGE_HANDLING_STATUS_LOOPED;
} else {
// mIsScanOngoing and mIsFullScanOngoing
messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
}
}
if (startScanNative(freqs, hiddenNetworks, workSource))
继续调用startScanNative
// TODO this is a temporary measure to bridge between WifiScanner and WifiStateMachine until
// scan functionality is refactored out of WifiStateMachine.
/**
* return true iff scan request is accepted
*/
private boolean startScanNative(final Set<Integer> freqs,
List<WifiScanner.ScanSettings.HiddenNetwork> hiddenNetworkList,
WorkSource workSource) {
WifiScanner.ScanSettings settings = new WifiScanner.ScanSettings();
if (freqs == null) {
settings.band = WifiScanner.WIFI_BAND_BOTH_WITH_DFS;
} else {
settings.band = WifiScanner.WIFI_BAND_UNSPECIFIED;
int index = 0;
settings.channels = new WifiScanner.ChannelSpec[freqs.size()];
for (Integer freq : freqs) {
settings.channels[index++] = new WifiScanner.ChannelSpec(freq);
}
}
settings.reportEvents = WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN
| WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT;
settings.hiddenNetworks =
hiddenNetworkList.toArray(
new WifiScanner.ScanSettings.HiddenNetwork[hiddenNetworkList.size()]);
WifiScanner.ScanListener nativeScanListener = new WifiScanner.ScanListener() {
// ignore all events since WifiStateMachine is registered for the supplicant events
@Override
public void onSuccess() {
}
@Override
public void onFailure(int reason, String description) {
mIsScanOngoing = false;
mIsFullScanOngoing = false;
}
@Override
public void onResults(WifiScanner.ScanData[] results) {
}
@Override
public void onFullResult(ScanResult fullScanResult) {
}
@Override
public void onPeriodChanged(int periodInMs) {
}
};
mWifiScanner.startScan(settings, nativeScanListener, workSource);
mIsScanOngoing = true;
mIsFullScanOngoing = (freqs == null);
lastScanFreqs = freqs;
return true;
}
由于freqs和workSource这两个参数为null,走settings.band = WifiScanner.WIFI_BAND_BOTH_WITH_DFS;所以settings.band是7,即频段为7
/** Both 2.4 GHz band and 5 GHz band; with DFS channels */
public static final int WIFI_BAND_BOTH_WITH_DFS = 7; /* both bands with DFS channels */
这边继续调用WifiScanner的startScan,settings不是null了,已经在startScanNative函数中被默认初始化过了。另外
WifiScanner.ScanListener nativeScanListener = new WifiScanner.ScanListener()
这边初始化了一个nativeScanListener委托给WifiScanner,从方法来看是有结果了会回调这个Listner,使用了委托模式。
2.3.4 WifiScanner
framework/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);
}
这里用了AsyncChannel,和aidl一样,也是IPC的一种方式。其实WifiScanner对应的服务端就是WifiScanningServiceImpl
下面来分析一下为什么WifiScanner对应的服务端就是WifiScanningServiceImpl,看一WifiScanner的构造函数
/**
* Create a new WifiScanner instance.
* Applications will almost always want to use
* {@link android.content.Context#getSystemService Context.getSystemService()} to retrieve
* the standard {@link android.content.Context#WIFI_SERVICE Context.WIFI_SERVICE}.
* @param context the application context
* @param service the Binder interface
* @param looper the Looper used to deliver callbacks
* @hide
*/
public WifiScanner(Context context, IWifiScanner service, Looper looper) {
mContext = context;
mService = service;
Messenger messenger = null;
try {
messenger = mService.getMessenger();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
if (messenger == null) {
throw new IllegalStateException("getMessenger() returned null! This is invalid.");
}
mAsyncChannel = new AsyncChannel();
mInternalHandler = new ServiceHandler(looper);
mAsyncChannel.connectSync(mContext, mInternalHandler, messenger);
// We cannot use fullyConnectSync because it sends the FULL_CONNECTION message
// synchronously, which causes WifiScanningService to receive the wrong replyTo value.
mAsyncChannel.sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION);
}
从WifiScanner的构造方法里可以看到InternalHandler/AsyncChannel/Messenger是完成IPC的桥梁。
另外WifiScanner的初始化是经由WifiStateMachine在WifiInjector里完成的。
// We can't do this in the constructor because WifiStateMachine is created before the
// wifi scanning service is initialized
if (mWifiScanner == null) {
mWifiScanner = mWifiInjector.getWifiScanner();
framework/opt/net/wifi/service/java/com/android/server/wifi/WifiInjector.java
/**
* Obtain an instance of WifiScanner.
* If it was not already created, then obtain an instance. Note, this must be done lazily since
* WifiScannerService is separate and created later.
*/
public synchronized WifiScanner getWifiScanner() {
if (mWifiScanner == null) {
mWifiScanner = new WifiScanner(mContext,
IWifiScanner.Stub.asInterface(ServiceManager.getService(
Context.WIFI_SCANNING_SERVICE)),
mWifiStateMachineHandlerThread.getLooper());
}
return mWifiScanner;
}
先看下在SystemServer会启动WifiScanningService服务
traceBeginAndSlog("StartWifiScanning");
mSystemServiceManager.startService(
"com.android.server.wifi.scanner.WifiScanningService");
traceEnd();
再看下WifiScanningService这个服务
public class WifiScanningService extends SystemService {
static final String TAG = "WifiScanningService";
private final WifiScanningServiceImpl mImpl;
private final HandlerThread mHandlerThread;
public WifiScanningService(Context context) {
super(context);
Log.i(TAG, "Creating " + Context.WIFI_SCANNING_SERVICE);
mHandlerThread = new HandlerThread("WifiScanningService");
mHandlerThread.start();
mImpl = new WifiScanningServiceImpl(getContext(), mHandlerThread.getLooper(),
WifiScannerImpl.DEFAULT_FACTORY, BatteryStatsService.getService(),
WifiInjector.getInstance());
}
@Override
public void onStart() {
Log.i(TAG, "Publishing " + Context.WIFI_SCANNING_SERVICE);
publishBinderService(Context.WIFI_SCANNING_SERVICE, mImpl);
}
/**
* Publish the service so it is accessible to other services and apps.
*/
protected final void publishBinderService(String name, IBinder service) {
publishBinderService(name, service, false);
}
/**
* Publish the service so it is accessible to other services and apps.
*/
protected final void publishBinderService(String name, IBinder service,
boolean allowIsolated) {
ServiceManager.addService(name, service, allowIsolated);
}
果不其然和WifiService一个套路,里面会new WifiScanningServiceImpl,经由SystemService的publishBinderService将自己加入到ServiceManager管理的Service中去,那么这里WifiScanner对应的服务端就是WifiScanningServiceImpl了。
现在就从WifiScanner进入到WifiScanningServiceImpl了
2.3.5 WifiScanningServiceImpl
framework/opt/net/wifi/service/java/com/android/server/wifi/scanner/WifiScanningServiceImpl.java
继而再看下getMessenger方法:
@Override
public Messenger getMessenger() {
if (mClientHandler != null) {
mLog.trace("getMessenger() uid=%").c(Binder.getCallingUid()).flush();
return new Messenger(mClientHandler);
}
loge("WifiScanningServiceImpl trying to get messenger w/o initialization");
return null;
}
这里梳理出来WifiScanningServiceImpl的ClientHander是处理WifiScanner发出的CMD_START_SINGLE_SCAN消息
framework/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) {
...
case WifiScanner.CMD_START_SINGLE_SCAN:
case WifiScanner.CMD_STOP_SINGLE_SCAN:
mSingleScanStateMachine.sendMessage(Message.obtain(msg));
break;
mSingleScanStateMachine = new WifiSingleScanStateMachine(mLooper);
这里又是状态模式,其中有个DriverStartedState继续处理,
framework/opt/net/wifi/service/java/com/android/server/wifi/scanner/WifiScanningServiceImpl.java
/**
* State representing when the driver is running. This state is not meant to be transitioned
* directly, but is instead indented 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 void exit() {
// clear scan results when scan mode is not active
mCachedScanResults.clear();
mWifiMetrics.incrementScanReturnEntry(
WifiMetricsProto.WifiLog.SCAN_FAILURE_INTERRUPTED,
mPendingScans.size());
sendOpFailedToAllAndClear(mPendingScans, WifiScanner.REASON_UNSPECIFIED,
"Scan was interrupted");
}
@Override
public boolean processMessage(Message msg) {
ClientInfo ci = mClients.get(msg.replyTo);
switch (msg.what) {
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, workSource)) {
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 {
logCallback("singleScanInvalidRequest", ci, handler, "bad request");
replyFailed(msg, WifiScanner.REASON_INVALID_REQUEST, "bad request");
mWifiMetrics.incrementScanReturnEntry(
WifiMetricsProto.WifiLog.SCAN_FAILURE_INVALID_CONFIGURATION, 1);
}
return HANDLED;
这里可以看到对上了,把我们千辛万苦传来的参数取了出来,虽然workSource就是个null,但是scanSettings的band是7
ScanSettings scanSettings =
scanParams.getParcelable(WifiScanner.SCAN_PARAMS_SCAN_SETTINGS_KEY);
WorkSource workSource =
scanParams.getParcelable(WifiScanner.SCAN_PARAMS_WORK_SOURCE_KEY);
之后返回一个操作成功的消息replySucceeded(msg);但这并不是搜索成功了,这里还没进行搜索scan;返回消息之后才会真正去进行搜索,
void replySucceeded(Message msg) {
if (msg.replyTo != null) {
Message reply = Message.obtain();
reply.what = WifiScanner.CMD_OP_SUCCEEDED;
reply.arg2 = msg.arg2;
if (msg.obj != null) {
reply.obj = msg.obj;
}
try {
msg.replyTo.send(reply);
mLog.trace("replySucceeded recvdMessage=%").c(msg.what).flush();
} catch (RemoteException e) {
// There's not much we can do if reply can't be sent!
}
} else {
// locally generated message; doesn't need a reply!
}
}
这边WifiScanner的ServiceHandler会收到并处理
frameworks/base/wifi/java/android/net/wifi/WifiScanner.java
private class ServiceHandler extends Handler {
ServiceHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED:
return;
case AsyncChannel.CMD_CHANNEL_DISCONNECTED:
Log.e(TAG, "Channel connection lost");
// This will cause all further async API calls on the WifiManager
// to fail and throw an exception
mAsyncChannel = null;
getLooper().quit();
return;
}
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) {
/* ActionListeners grouped together */
case CMD_OP_SUCCEEDED :
((ActionListener) listener).onSuccess();
break;
最后再调用到我们在WifiStateMachine里初始化好的listener的success方法,但是这里是空的
frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiStateMachine.java
WifiScanner.ScanListener nativeScanListener = new WifiScanner.ScanListener() {
// ignore all events since WifiStateMachine is registered for the supplicant events
@Override
public void onSuccess() {
}
@Override
public void onFailure(int reason, String description) {
mIsScanOngoing = false;
mIsFullScanOngoing = false;
}
@Override
public void onResults(WifiScanner.ScanData[] results) {
}
@Override
public void onFullResult(ScanResult fullScanResult) {
}
@Override
public void onPeriodChanged(int periodInMs) {
}
};
接着前面的DriverStartedState进行分析返回操作成功消息返回一个操作成功的消息replySucceeded(msg);之后的代码如下
framework/opt/net/wifi/service/java/com/android/server/wifi/scanner/WifiScanningServiceImpl.java
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 {
logCallback("singleScanInvalidRequest", ci, handler, "bad request");
replyFailed(msg, WifiScanner.REASON_INVALID_REQUEST, "bad request");
mWifiMetrics.incrementScanReturnEntry(
WifiMetricsProto.WifiLog.SCAN_FAILURE_INVALID_CONFIGURATION, 1);
}
return HANDLED;
这边代码意思是如果正在搜索那么就不重新开始新的scan了,否则tryToStartNewScan()
然后看下tryToStartNewScan()
framework/opt/net/wifi/service/java/com/android/server/wifi/scanner/WifiScanningServiceImpl.java
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();
List<WifiNative.HiddenNetwork> hiddenNetworkList = new ArrayList<>();
for (RequestInfo<ScanSettings> entry : mPendingScans) {
channels.addChannels(entry.settings);
if (entry.settings.hiddenNetworks != null) {
for (int i = 0; i < entry.settings.hiddenNetworks.length; i++) {
WifiNative.HiddenNetwork hiddenNetwork = new WifiNative.HiddenNetwork();
hiddenNetwork.ssid = entry.settings.hiddenNetworks[i].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 (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 (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
先看一下mScannerImpl是怎么来的
framework/opt/net/wifi/service/java/com/android/server/wifi/scanner/WifiScanningServiceImpl.java
private WifiScannerImpl mScannerImpl;
mScannerImpl = mScannerImplFactory.create(mContext, mLooper, mClock);
frameworks/opt/net/wifi/service/java/com/android/server/wifi/scanner/WifiScannerImpl.java
public abstract class WifiScannerImpl {
/**
* A factory that create a {@link com.android.server.wifi.scanner.WifiScannerImpl}
*/
public static interface WifiScannerImplFactory {
WifiScannerImpl create(Context context, Looper looper, Clock clock);
}
/**
* Factory that create the implementation that is most appropriate for the system.
* This factory should only ever be used once.
*/
public static final WifiScannerImplFactory DEFAULT_FACTORY = new WifiScannerImplFactory() {
public WifiScannerImpl create(Context context, Looper looper, Clock clock) {
WifiNative wifiNative = WifiInjector.getInstance().getWifiNative();
WifiMonitor wifiMonitor = WifiInjector.getInstance().getWifiMonitor();
if (wifiNative.getBgScanCapabilities(new WifiNative.ScanCapabilities())) {
return new HalWifiScannerImpl(context, wifiNative, wifiMonitor, looper, clock);
} else {
return new WificondScannerImpl(context, wifiNative, wifiMonitor, looper,
clock);
}
}
};
从mScannerImpl = mScannerImplFactory.create(mContext, mLooper, mClock);知道。
mScannerImpl是通过factory创建出来的,那么这个factory是如何创建的?mScannerImplFactory是怎么来的?
先来看一下WifiScanningService
frameworks/opt/net/wifi/service/java/com/android/server/wifi/scanner/WifiScanningService.java
mImpl = new WifiScanningServiceImpl(getContext(), mHandlerThread.getLooper(),
WifiScannerImpl.DEFAULT_FACTORY, BatteryStatsService.getService(),
WifiInjector.getInstance());
再看一下WifiScanningServiceImpl的构造函数
frameworks/opt/net/wifi/service/java/com/android/server/wifi/scanner/WifiScanningService.java
WifiScanningServiceImpl(Context context, Looper looper,
WifiScannerImpl.WifiScannerImplFactory scannerImplFactory, IBatteryStats batteryStats,
WifiInjector wifiInjector) {
mContext = context;
mLooper = looper;
mScannerImplFactory = scannerImplFactory;
mBatteryStats = batteryStats;
mClients = new ArrayMap<>();
mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
mWifiMetrics = wifiInjector.getWifiMetrics();
mClock = wifiInjector.getClock();
mLog = wifiInjector.makeLog(TAG);
mFrameworkFacade = wifiInjector.getFrameworkFacade();
mPreviousSchedule = null;
}
原来mScannerImplFactory是通过new WifiScanningServiceImpl创建的参数,然后在WifiScanningServiceImpl构造函数中赋值的mScannerImplFactory = scannerImplFactory;我们可以看到fmScannerImplFactory其实就是WifiScannerImpl.DEFAULT_FACTORY
frameworks/opt/net/wifi/service/java/com/android/server/wifi/scanner/WifiScannerImpl.java
public static final WifiScannerImplFactory DEFAULT_FACTORY = new WifiScannerImplFactory() {
public WifiScannerImpl create(Context context, Looper looper, Clock clock) {
WifiNative wifiNative = WifiInjector.getInstance().getWifiNative();
WifiMonitor wifiMonitor = WifiInjector.getInstance().getWifiMonitor();
if (wifiNative.getBgScanCapabilities(new WifiNative.ScanCapabilities())) {
return new HalWifiScannerImpl(context, wifiNative, wifiMonitor, looper, clock);
} else {
return new WificondScannerImpl(context, wifiNative, wifiMonitor, looper,
clock);
}
}
};
可以看到里面返回的是对象HalWifiScannerImpl或者WificondScannerImpl,所以前面的mScannerImpl.startSingleScan其实调用的是这两个对象的startSingleScan方法
分别看下这两个对象实现的HalWifiScannerImpl.startSingleScan方法
HalWifiScannerImpl
frameworks/opt/net/wifi/service/java/com/android/server/wifi/scanner/HalWifiScannerImpl.java
public boolean startSingleScan(WifiNative.ScanSettings settings,
WifiNative.ScanEventHandler eventHandler) {
return mWificondScannerDelegate.startSingleScan(settings, eventHandler);
}
mWificondScannerDelegate =
new WificondScannerImpl(context, wifiNative, wifiMonitor, mChannelHelper,
looper, clock);
所以HalWifiScannerImpl.startSingleScan其实就是WificondScannerImpl.startSingleScan
所以前面的mScannerImpl.startSingleScan其实真正调用的是WificondScannerImpl.startSingleScan
2.3.6 WificondScannerImpl
frameworks/opt/net/wifi/service/java/com/android/server/wifi/scanner/WificondScannerImpl.java
@Override
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;
}
if (mPendingSingleScanSettings != null
|| (mLastScanSettings != null && mLastScanSettings.singleScanActive)) {
Log.w(TAG, "A single scan is already running");
return false;
}
synchronized (mSettingsLock) {
mPendingSingleScanSettings = settings;
mPendingSingleScanEventHandler = eventHandler;
processPendingScans();
return true;
}
}
private void processPendingScans() {
synchronized (mSettingsLock) {
// Wait for the active scan result to come back to reschedule other scans,
// unless if HW pno scan is running. Hw PNO scans are paused it if there
// are other pending scans,
if (mLastScanSettings != null && !mLastScanSettings.hwPnoScanActive) {
return;
}
ChannelCollection allFreqs = mChannelHelper.createChannelCollection();
Set<String> hiddenNetworkSSIDSet = new HashSet<>();
final LastScanSettings newScanSettings =
new LastScanSettings(mClock.getElapsedSinceBootMillis());
// Update scan settings if there is a pending scan
if (!mBackgroundScanPaused) {
if (mPendingBackgroundScanSettings != null) {
mBackgroundScanSettings = mPendingBackgroundScanSettings;
mBackgroundScanEventHandler = mPendingBackgroundScanEventHandler;
mNextBackgroundScanPeriod = 0;
mPendingBackgroundScanSettings = null;
mPendingBackgroundScanEventHandler = null;
mBackgroundScanPeriodPending = true;
}
if (mBackgroundScanPeriodPending && mBackgroundScanSettings != null) {
int reportEvents = WifiScanner.REPORT_EVENT_NO_BATCH; // default to no batch
for (int bucket_id = 0; bucket_id < mBackgroundScanSettings.num_buckets;
++bucket_id) {
WifiNative.BucketSettings bucket =
mBackgroundScanSettings.buckets[bucket_id];
if (mNextBackgroundScanPeriod % (bucket.period_ms
/ mBackgroundScanSettings.base_period_ms) == 0) {
if ((bucket.report_events
& WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN) != 0) {
reportEvents |= WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN;
}
if ((bucket.report_events
& WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT) != 0) {
reportEvents |= WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT;
}
// only no batch if all buckets specify it
if ((bucket.report_events
& WifiScanner.REPORT_EVENT_NO_BATCH) == 0) {
reportEvents &= ~WifiScanner.REPORT_EVENT_NO_BATCH;
}
allFreqs.addChannels(bucket);
}
}
if (!allFreqs.isEmpty()) {
newScanSettings.setBackgroundScan(mNextBackgroundScanId++,
mBackgroundScanSettings.max_ap_per_scan, reportEvents,
mBackgroundScanSettings.report_threshold_num_scans,
mBackgroundScanSettings.report_threshold_percent);
}
mNextBackgroundScanPeriod++;
mBackgroundScanPeriodPending = false;
mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
mClock.getElapsedSinceBootMillis()
+ mBackgroundScanSettings.base_period_ms,
BACKGROUND_PERIOD_ALARM_TAG, mScanPeriodListener, mEventHandler);
}
}
if (mPendingSingleScanSettings != null) {
boolean reportFullResults = false;
ChannelCollection singleScanFreqs = mChannelHelper.createChannelCollection();
for (int i = 0; i < mPendingSingleScanSettings.num_buckets; ++i) {
WifiNative.BucketSettings bucketSettings =
mPendingSingleScanSettings.buckets[i];
if ((bucketSettings.report_events
& WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT) != 0) {
reportFullResults = true;
}
singleScanFreqs.addChannels(bucketSettings);
allFreqs.addChannels(bucketSettings);
}
newScanSettings.setSingleScan(reportFullResults, singleScanFreqs,
mPendingSingleScanEventHandler);
WifiNative.HiddenNetwork[] hiddenNetworks =
mPendingSingleScanSettings.hiddenNetworks;
if (hiddenNetworks != null) {
int numHiddenNetworks =
Math.min(hiddenNetworks.length, MAX_HIDDEN_NETWORK_IDS_PER_SCAN);
for (int i = 0; i < numHiddenNetworks; i++) {
hiddenNetworkSSIDSet.add(hiddenNetworks[i].ssid);
}
}
mPendingSingleScanSettings = null;
mPendingSingleScanEventHandler = null;
}
if (newScanSettings.backgroundScanActive || newScanSettings.singleScanActive) {
boolean success = false;
Set<Integer> freqs;
if (!allFreqs.isEmpty()) {
pauseHwPnoScan();
freqs = allFreqs.getScanFreqs();
success = mWifiNative.scan(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 for");
}
if (success) {
// TODO handle scan timeout
if (DBG) {
Log.d(TAG, "Starting wifi scan for freqs=" + freqs
+ ", background=" + newScanSettings.backgroundScanActive
+ ", single=" + newScanSettings.singleScanActive);
}
mLastScanSettings = newScanSettings;
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() {
public void run() {
if (newScanSettings.singleScanEventHandler != null) {
newScanSettings.singleScanEventHandler
.onScanStatus(WifiNative.WIFI_SCAN_FAILED);
}
}
});
// TODO(b/27769665) background scans should be failed too if scans fail enough
}
} else if (isHwPnoScanRequired()) {
newScanSettings.setHwPnoScan(mPnoSettings.networkList, mPnoEventHandler);
boolean status;
// If the PNO network list has changed from the previous request, ensure that
// we bypass the debounce logic and restart PNO scan.
if (isDifferentPnoScanSettings(newScanSettings)) {
status = restartHwPnoScan(mPnoSettings);
} else {
status = startHwPnoScan(mPnoSettings);
}
if (status) {
mLastScanSettings = newScanSettings;
} else {
Log.e(TAG, "Failed to start PNO scan");
// indicate scan failure async
mEventHandler.post(new Runnable() {
public void run() {
if (mPnoEventHandler != null) {
mPnoEventHandler.onPnoScanFailed();
}
// Clean up PNO state, we don't want to continue PNO scanning.
mPnoSettings = null;
mPnoEventHandler = null;
}
});
}
}
}
}
代码很长的,但我们重点看下面这一句
success = mWifiNative.scan(freqs, hiddenNetworkSSIDSet);
最终还是会调用到WifiNative的scan方法,毕竟上层的搜索都是空的,还要底层配合。
2.3.7 WifiNative
frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiNative.java
/**
* Start a scan using wificond for the given parameters.
* @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(Set<Integer> freqs, Set<String> hiddenNetworkSSIDs) {
return mWificondControl.scan(freqs, hiddenNetworkSSIDs);
}
2.3.8 WificondControl
frameworks/opt/net/wifi/service/java/com/android/server/wifi/WificondControl.java
/**
* Start a scan using wificond for the given parameters.
* @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(Set<Integer> freqs, Set<String> hiddenNetworkSSIDs) {
if (mWificondScanner == null) {
Log.e(TAG, "No valid wificond scanner interface handler");
return false;
}
SingleScanSettings settings = new SingleScanSettings();
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 mWificondScanner.scan(settings);
} catch (RemoteException e1) {
Log.e(TAG, "Failed to request scan due to remote exception");
}
return false;
}
这边又调用到WificondScanner里去了,下面来看一下mWificondScanner是怎么来的,是在setupDriverForClientMode函数中赋值得到的
frameworks/opt/net/wifi/service/java/com/android/server/wifi/WificondControl.java
/**
* Setup driver for client mode via wificond.
* @return An IClientInterface as wificond client interface binder handler.
* Returns null on failure.
*/
public IClientInterface setupDriverForClientMode() {
Log.d(TAG, "Setting up driver for client mode");
mWificond = mWifiInjector.makeWificond();
if (mWificond == null) {
Log.e(TAG, "Failed to get reference to wificond");
return null;
}
IClientInterface clientInterface = null;
try {
clientInterface = mWificond.createClientInterface();
} 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
mClientInterface = clientInterface;
try {
mClientInterfaceName = clientInterface.getInterfaceName();
mWificondScanner = mClientInterface.getWifiScannerImpl();
if (mWificondScanner == null) {
Log.e(TAG, "Failed to get WificondScannerImpl");
return null;
}
Binder.allowBlocking(mWificondScanner.asBinder());
mScanEventHandler = new ScanEventHandler();
mWificondScanner.subscribeScanEvents(mScanEventHandler);
mPnoScanEventHandler = new PnoScanEventHandler();
mWificondScanner.subscribePnoScanEvents(mPnoScanEventHandler);
} catch (RemoteException e) {
Log.e(TAG, "Failed to refresh wificond scanner due to remote exception");
}
return clientInterface;
}
我们把上面的代码重点抽取出来
public IClientInterface setupDriverForClientMode() {
mWificond = mWifiInjector.makeWificond();
clientInterface = mWificond.createClientInterface();
// Refresh Handlers
mClientInterface = clientInterface;
mWificondScanner = mClientInterface.getWifiScannerImpl();
}
原来mWificondScanner = mClientInterface.getWifiScannerImpl();是这么来的
这里就涉及到java与c++之间的aidl-cpp通信。我们有空再慢慢梳理
2.4 Native
这里我们先到代码中搜一下getWifiScannerImpl方法实现,这里看到只有client_interface_binder.cpp有对应实现
system/connectivity/wificond/client_interface_binder.cpp
Status ClientInterfaceBinder::getWifiScannerImpl(
sp<IWifiScannerImpl>* out_wifi_scanner_impl) {
if (impl_ == nullptr) {
*out_wifi_scanner_impl = nullptr;
return Status::ok();
}
*out_wifi_scanner_impl = impl_->GetScanner();
return Status::ok();
}
所以mWificondScanner = mClientInterface.getWifiScannerImpl();最终一定会调用到client_interface_binder.cpp中的ClientInterfaceBinder::getWifiScannerImpl
这里我们知道传入的参数是IWifiScannerImpl的实现类,而impl_是ClientInterfaceImpl对象。
这里我们主要关注*out_wifi_scanner_impl = impl_->GetScanner();
而GetScanner方法:
system/connectivity/wificond/client_interface_impl.h
const android::sp<ScannerImpl> GetScanner() { return scanner_; };
直接返回scanner_
android::sp<ScannerImpl> scanner_;
看来scanner_是一个ScannerImpl对象
看下ScannerImpl这个类的scan方法
system/connectivity/wificond/scanning/scanner_impl.cpp
Status ScannerImpl::scan(const SingleScanSettings& scan_settings,
bool* out_success) {
if (!CheckIsValid()) {
*out_success = false;
return Status::ok();
}
if (scan_started_) {
LOG(WARNING) << "Scan already started";
}
// Only request MAC address randomization when station is not associated.
bool request_random_mac = wiphy_features_.supports_random_mac_oneshot_scan &&
!client_interface_->IsAssociated();
// Initialize it with an empty ssid for a wild card scan.
vector<vector<uint8_t>> ssids = {{}};
vector<vector<uint8_t>> skipped_scan_ssids;
for (auto& network : scan_settings.hidden_networks_) {
if (ssids.size() + 1 > scan_capabilities_.max_num_scan_ssids) {
skipped_scan_ssids.emplace_back(network.ssid_);
continue;
}
ssids.push_back(network.ssid_);
}
LogSsidList(skipped_scan_ssids, "Skip scan ssid for single scan");
vector<uint32_t> freqs;
for (auto& channel : scan_settings.channel_settings_) {
freqs.push_back(channel.frequency_);
}
int error_code = 0;
if (!scan_utils_->Scan(interface_index_, request_random_mac, ssids, freqs,
&error_code)) {
CHECK(error_code != ENODEV) << "Driver is in a bad state, restarting wificond";
*out_success = false;
return Status::ok();
}
scan_started_ = true;
*out_success = true;
return Status::ok();
}
可以看到这里会调用到scan_utils方法:
scan_utils_->Scan(interface_index_, request_random_mac, ssids, freqs,
&error_code)
2.5 scan_utils.cpp
bool ScanUtils::Scan(uint32_t interface_index,
bool request_random_mac,
const vector<vector<uint8_t>>& ssids,
const vector<uint32_t>& freqs,
int* error_code) {
NL80211Packet trigger_scan(
netlink_manager_->GetFamilyId(),
NL80211_CMD_TRIGGER_SCAN,
netlink_manager_->GetSequenceNumber(),
getpid());
// If we do not use NLM_F_ACK, we only receive a unicast repsonse
// when there is an error. If everything is good, scan results notification
// will only be sent through multicast.
// If NLM_F_ACK is set, there will always be an unicast repsonse, either an
// ERROR or an ACK message. The handler will always be called and removed by
// NetlinkManager.
trigger_scan.AddFlag(NLM_F_ACK);
NL80211Attr<uint32_t> if_index_attr(NL80211_ATTR_IFINDEX, interface_index);
NL80211NestedAttr ssids_attr(NL80211_ATTR_SCAN_SSIDS);
for (size_t i = 0; i < ssids.size(); i++) {
ssids_attr.AddAttribute(NL80211Attr<vector<uint8_t>>(i, ssids[i]));
}
NL80211NestedAttr freqs_attr(NL80211_ATTR_SCAN_FREQUENCIES);
for (size_t i = 0; i < freqs.size(); i++) {
freqs_attr.AddAttribute(NL80211Attr<uint32_t>(i, freqs[i]));
}
trigger_scan.AddAttribute(if_index_attr);
trigger_scan.AddAttribute(ssids_attr);
// An absence of NL80211_ATTR_SCAN_FREQUENCIES attribue informs kernel to
// scan all supported frequencies.
if (!freqs.empty()) {
trigger_scan.AddAttribute(freqs_attr);
}
if (request_random_mac) {
trigger_scan.AddAttribute(
NL80211Attr<uint32_t>(NL80211_ATTR_SCAN_FLAGS,
NL80211_SCAN_FLAG_RANDOM_ADDR));
}
// We are receiving an ERROR/ACK message instead of the actual
// scan results here, so it is OK to expect a timely response because
// kernel is supposed to send the ERROR/ACK back before the scan starts.
vector<unique_ptr<const NL80211Packet>> response;
if (!netlink_manager_->SendMessageAndGetAckOrError(trigger_scan,
error_code)) {
// Logging is done inside |SendMessageAndGetAckOrError|.
return false;
}
if (*error_code != 0) {
LOG(ERROR) << "NL80211_CMD_TRIGGER_SCAN failed: " << strerror(*error_code);
return false;
}
return true;
}
我们可以看到 netlink_manager_->SendMessageAndGetAckOrError这个函数把trigger_scan中的NL80211_CMD_TRIGGER_SCAN下发给kernel,并从等到应答
2.6 netlink_manager.cpp
bool NetlinkManager::SendMessageAndGetAckOrError(const NL80211Packet& packet,
int* error_code) {
unique_ptr<const NL80211Packet> response;
if (!SendMessageAndGetSingleResponseOrError(packet, &response)) {
return false;
}
uint16_t type = response->GetMessageType();
if (type != NLMSG_ERROR) {
LOG(ERROR) << "Receive unexpected message type :" << type;
return false;
}
*error_code = response->GetErrorCode();
return true;
}
bool NetlinkManager::SendMessageAndGetSingleResponseOrError(
const NL80211Packet& packet,
unique_ptr<const NL80211Packet>* response) {
vector<unique_ptr<const NL80211Packet>> response_vec;
if (!SendMessageAndGetResponses(packet, &response_vec)) {
return false;**重点内容**
}
if (response_vec.size() != 1) {
LOG(ERROR) << "Unexpected response size: " << response_vec.size();
return false;
}
*response = std::move(response_vec[0]);
return true;
}
bool NetlinkManager::SendMessageAndGetResponses(
const NL80211Packet& packet,
vector<unique_ptr<const NL80211Packet>>* response) {
if (!SendMessageInternal(packet, sync_netlink_fd_.get())) {
return false;
}
// Polling netlink socket, waiting for GetFamily reply.
struct pollfd netlink_output;
memset(&netlink_output, 0, sizeof(netlink_output));
netlink_output.fd = sync_netlink_fd_.get();
netlink_output.events = POLLIN;
uint32_t sequence = packet.GetMessageSequence();
int time_remaining = kMaximumNetlinkMessageWaitMilliSeconds;
// Multipart messages may come with seperated datagrams, ending with a
// NLMSG_DONE message.
// ReceivePacketAndRunHandler() will remove the handler after receiving a
// NLMSG_DONE message.
message_handlers_[sequence] = std::bind(AppendPacket, response, _1);
while (time_remaining > 0 &&
message_handlers_.find(sequence) != message_handlers_.end()) {
nsecs_t interval = systemTime(SYSTEM_TIME_MONOTONIC);
int poll_return = poll(&netlink_output,
1,
time_remaining);
if (poll_return == 0) {
LOG(ERROR) << "Failed to poll netlink fd: time out ";
message_handlers_.erase(sequence);
return false;
} else if (poll_return == -1) {
LOG(ERROR) << "Failed to poll netlink fd: " << strerror(errno);
message_handlers_.erase(sequence);
return false;
}
ReceivePacketAndRunHandler(sync_netlink_fd_.get());
interval = systemTime(SYSTEM_TIME_MONOTONIC) - interval;
time_remaining -= static_cast<int>(ns2ms(interval));
}
if (time_remaining <= 0) {
LOG(ERROR) << "Timeout waiting for netlink reply messages";
message_handlers_.erase(sequence);
return false;
}
return true;
}
bool NetlinkManager::SendMessageInternal(const NL80211Packet& packet, int fd) {
const vector<uint8_t>& data = packet.GetConstData();
ssize_t bytes_sent =
TEMP_FAILURE_RETRY(send(fd, data.data(), data.size(), 0));
if (bytes_sent == -1) {
LOG(ERROR) << "Failed to send netlink message: " << strerror(errno);
return false;
}
return true;
}
3.总结