通过 WifiScanner.java 中 WifiScanner 类的 registerScanListener 方法注册 Scan 结果的回调监听句柄,实际上内部通过 AsyncChannel 向 WifiScanningService 层发送了 CMD_REGISTER_SCAN_LISTENER 消息:
/**
* Register a listener that will receive results from all single scans.
* Either the {@link ScanListener#onSuccess()} or {@link ScanListener#onFailure(int, String)}
* method will be called once when the listener is registered.
* Afterwards (assuming onSuccess was called), all subsequent single scan results will be
* delivered to the listener. It is possible that onFullResult will not be called for all
* results of the first scan if the listener was registered during the scan.
*
* @param executor the Executor on which to run the callback.
* @param listener specifies the object to report events to. This object is also treated as a
* key for this request, and must also be specified to cancel the request.
* Multiple requests should also not share this object.
*/
@RequiresPermission(Manifest.permission.NETWORK_STACK)
public void registerScanListener(@NonNull @CallbackExecutor Executor executor,
@NonNull ScanListener listener) {
Objects.requireNonNull(executor, "executor cannot be null");
Objects.requireNonNull(listener, "listener cannot be null");
int key = addListener(listener, executor);
if (key == INVALID_KEY) return;
validateChannel();
mAsyncChannel.sendMessage(CMD_REGISTER_SCAN_LISTENER, 0, key);
}
class WifiScanningService 定义在 WifiScanningService.java 文件中,其实际的实现在 WifiScanningServiceImpl 类中,向系统注册并提供 WIFI_SCANNING_SERVICE 服务:
/**
* Service implementing Wi-Fi scanning functionality. Delegates actual interface
* implementation to WifiScanningServiceImpl.
*/
public class WifiScanningService extends SystemService {
static final String TAG = "WifiScanningService";
private final WifiScanningServiceImpl mImpl;
private final HandlerThread mHandlerThread;
public WifiScanningService(Context contextBase) {
super(new WifiContext(contextBase));
Log.i(TAG, "Creating " + Context.WIFI_SCANNING_SERVICE);
mHandlerThread = new HandlerThread("WifiScanningService");
mHandlerThread.start();
mImpl = new WifiScanningServiceImpl(getContext(), mHandlerThread.getLooper(),
WifiScannerImpl.DEFAULT_FACTORY,
getContext().getSystemService(BatteryStatsManager.class),
WifiInjector.getInstance());
}
@Override
public void onStart() {
Log.i(TAG, "Publishing " + Context.WIFI_SCANNING_SERVICE);
publishBinderService(Context.WIFI_SCANNING_SERVICE, mImpl);
}
@Override
public void onBootPhase(int phase) {
if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
Log.i(TAG, "Starting " + Context.WIFI_SCANNING_SERVICE);
mImpl.startService();
}
}
}
服务的实际注册发生在 WifiFrameworkInitializer 中的 registerServiceWrappers 方法中,与 WIFI_SERVICE 等一起注册。客户端则在 WifiScanner 类中实现,在文件 WifiScanner.java 文件中。
接下来看在服务端 WifiScanningServiceImpl 中的处理过程:
1. 消息处理发生在 ClientHandler 内部类中,其 handleMessage 接口进行处理,实际上就是将对应的请求信息添加到 mSingleScanListeners 链中,其类型为 RequestList<>,添加方法为 addRequest,也是内部私有实现的类;
2. 消息回送发生在 reportFullScanResult 和 reportScanResults 接口中,通知消息有 CMD_SCAN_RESULT,CMD_SINGLE_SCAN_COMPLETED 和 CMD_FULL_SCAN_RESULT 三种;
WifiConnectivityManager 类中通过 retrieveWifiScanner 方法创建 WifiScanner 对象 mScanner,使其指向 WIFI_SCANNING_SERVICE 服务,同时向服务端注册 Scan 监听者:
/**
* Helper method to populate WifiScanner handle. This is done lazily because
* WifiScanningService is started after WifiService.
*/
private void retrieveWifiScanner() {
if (mScanner != null) return;
mScanner = mWifiInjector.getWifiScanner();
checkNotNull(mScanner);
// Register for all single scan results
mScanner.registerScanListener(new HandlerExecutor(mEventHandler), mAllSingleScanListener);
}
/**
* Start WifiConnectivityManager
*/
private void start() {
if (mRunning) return;
retrieveWifiScanner();
mConnectivityHelper.getFirmwareRoamingInfo();
mBssidBlocklistMonitor.clearBssidBlocklist();
mWifiChannelUtilization.init(mStateMachine.getWifiLinkLayerStats());
if (mContext.getResources().getBoolean(R.bool.config_wifiEnablePartialInitialScan)) {
setInitialScanState(INITIAL_SCAN_STATE_START);
}
mRunning = true;
mLatestCandidates = null;
mLatestCandidatesTimestampMs = 0;
}
注册事件发生在 start 调用中,在 WifiConnectivityManager 启动的时候进行,mAllSingleScanListener 为 AllSingleScanListener 类对象,实现了 WifiScanner 的 ScanListener 接口类,在服务端进行 reportScanResults 等操作时对应的方法被调用用来处理回调事件。
实际的通知是调用了 ClientInfo 类的 reportEvent 方法,而 ClientInfo 又被分别继承了成为内部和外部,内部叫 InternalClientInfo,而外部叫 ExternalClientInfo,两者的消息机制有差异,External 使用了 AsyncChannel,其 sendMessage 方法被调用,而 Internal 则采用了 Messenger 的 send 方法进行发送,两者的差别和实现细节后面的文章再分析,在 WifiConnectivityManager 的 AllSingleScanListener 注册过程中在 ClientHandler 的 handleMessage 中处理,这里的 ClientInfo 为 ExternalClientInfo 对象,因此后面采用它的 reportEvent 发小消息上报。WifiScanner 的 ServiceHandler 中的 handleMessage 处理对应的消息,执行了 scanListener 的 onResults方法。
这里消息的处理还是在 Client 和 Server 之间通过 AsyncChannel 的双向通道,两者之间有 Handler 对象来处理对方发送过来的消息,从而进行相应的操作;在 Server 端实际上执行了 executor 线程来运行对应的处理过程,这里是 onResults 方法。
在 Client 端实际上是 ClientHandler 继承了 WifiHandler 进而继承了 Handler,其 handleMessage 方法在处理 CMD_REGISTER_SCAN_LISTENER 消息的时候将对应的 Request 加入到 mSingleScanListeners 中,而用于生成 RequestInfo 的 ClientInfo 对象由 mClients 的 get 方法从 msg 的 replyTo 对象(Messenger)获取到,mClients 则是 ArrayMap<Messenger, ClientInfo> 对象,每一个 AsyncChannel 在初始化过程中由 ClientInfo 的 register 方法进行注册,生成 Messenger 和 ClientInfo 对,在 ClientHandler 收到了 AsyncChannel.CMD_CHANNEL_FULL_CONNECTION 消息进行处理的时候进行的,对应的 ClientHandler 对象在 WifiScanningServiceImpl 的 startService 中创建,而 Client 端的 ServiceHandler 则是在 WifiScanner 构造函数中创建,在这里获取了一个 Service 对应的 Messenger 对象,创建了 AsyncChannel 对象并通过其 connectSync 方法将 ServiceHandler 对象 mInternalHandler 与 messenger 连接起来,并且发送了 AsyncChannel.CMD_CHANNEL_FULL_CONNECTION 消息:
/**
* 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 for {@link Context#WIFI_SCANNING_SERVICE}
* @param looper the Looper used to deliver callbacks
*
* @hide
*/
public WifiScanner(@NonNull Context context, @NonNull IWifiScanner service,
@NonNull 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);
}
回到 WifiConnectivityManager 中的消息处理过程,假设是报告扫描结果,则 AllSingleScanListener 类中的 onResults 方法被调用,其处理过程如下:
@Override
public void onResults(WifiScanner.ScanData[] results) {
if (!mWifiEnabled || !mAutoJoinEnabled) {
clearScanDetails();
mWaitForFullBandScanResults = false;
return;
}
// We treat any full band scans (with DFS or not) as "full".
boolean isFullBandScanResults = false;
if (results != null && results.length > 0) {
isFullBandScanResults =
WifiScanner.isFullBandScan(results[0].getBandScanned(), true);
}
// Full band scan results only.
if (mWaitForFullBandScanResults) {
if (!isFullBandScanResults) {
localLog("AllSingleScanListener waiting for full band scan results.");
clearScanDetails();
return;
} else {
mWaitForFullBandScanResults = false;
}
}
if (results != null && results.length > 0) {
mWifiMetrics.incrementAvailableNetworksHistograms(mScanDetails,
isFullBandScanResults);
}
if (mNumScanResultsIgnoredDueToSingleRadioChain > 0) {
Log.i(TAG, "Number of scan results ignored due to single radio chain scan: "
+ mNumScanResultsIgnoredDueToSingleRadioChain);
}
boolean wasConnectAttempted = handleScanResults(mScanDetails,
ALL_SINGLE_SCAN_LISTENER, isFullBandScanResults);
clearScanDetails();
// Update metrics to see if a single scan detected a valid network
// while PNO scan didn't.
// Note: We don't update the background scan metrics any more as it is
// not in use.
if (mPnoScanStarted) {
if (wasConnectAttempted) {
mWifiMetrics.incrementNumConnectivityWatchdogPnoBad();
} else {
mWifiMetrics.incrementNumConnectivityWatchdogPnoGood();
}
}
// Check if we are in the middle of initial partial scan
if (mInitialScanState == INITIAL_SCAN_STATE_AWAITING_RESPONSE) {
// Done with initial scan
setInitialScanState(INITIAL_SCAN_STATE_COMPLETE);
if (wasConnectAttempted) {
Log.i(TAG, "Connection attempted with the reduced initial scans");
schedulePeriodicScanTimer(
getScheduledSingleScanIntervalMs(mCurrentSingleScanScheduleIndex));
mWifiMetrics.reportInitialPartialScan(mInitialPartialScanChannelCount, true);
mInitialPartialScanChannelCount = 0;
} else {
Log.i(TAG, "Connection was not attempted, issuing a full scan");
startConnectivityScan(SCAN_IMMEDIATELY);
mFailedInitialPartialScan = true;
}
} else if (mInitialScanState == INITIAL_SCAN_STATE_COMPLETE) {
if (mFailedInitialPartialScan && wasConnectAttempted) {
// Initial scan failed, but following full scan succeeded
mWifiMetrics.reportInitialPartialScan(mInitialPartialScanChannelCount, false);
}
mFailedInitialPartialScan = false;
mInitialPartialScanChannelCount = 0;
}
}
具体的处理过程分析如下:
1. 判断 WiFi 开启(mWifiEnabled),并且打开了自动链接配置(mAutoJoinEnabled),否则退出;
2. 确定是否 FullBandScan 的结果(isFullBandScanResults);
3. 判断是否需要等带 FullBandScan 的结果,并根据第 2 步判断的结果来确定是否继续处理或者等待;
4. 更新 mWifiMetrics 的相关信息,关于 WifiMetrics 后面再分析;
5. 记录一些 Log 信息;
6. 最重要的 handleScanResults 登场,实际的扫描结果处理发生在该接口中,稍后详细分析该函数实现;
7. 处理之后清楚扫描的结果内容;
8. 继续更新 mWifiMetrics 相关的信息;
9. 查询当前的扫描状态,并进行相应的更新以及 mWifiMetrics 处理,如果链接过程并未进行,则触发 WiFi 的连接过程(startConnectivityScan,并且立即连接 SCAN_IMMEIDATELY);
下面分析 handleScanResults 方法
/**
* Handles 'onResult' callbacks for the Periodic, Single & Pno ScanListener.
* Executes selection of potential network candidates, initiation of connection attempt to that
* network.
*
* @return true - if a candidate is selected by WifiNetworkSelector
* false - if no candidate is selected by WifiNetworkSelector
*/
private boolean handleScanResults(List<ScanDetail> scanDetails, String listenerName,
boolean isFullScan) {
mWifiChannelUtilization.refreshChannelStatsAndChannelUtilization(
mStateMachine.getWifiLinkLayerStats(), WifiChannelUtilization.UNKNOWN_FREQ);
updateUserDisabledList(scanDetails);
// Check if any blocklisted BSSIDs can be freed.
Set<String> bssidBlocklist = mBssidBlocklistMonitor.updateAndGetBssidBlocklist();
if (mStateMachine.isSupplicantTransientState()) {
localLog(listenerName
+ " onResults: No network selection because supplicantTransientState is "
+ mStateMachine.isSupplicantTransientState());
return false;
}
localLog(listenerName + " onResults: start network selection");
List<WifiCandidates.Candidate> candidates = mNetworkSelector.getCandidatesFromScan(
scanDetails, bssidBlocklist, mWifiInfo, mStateMachine.isConnected(),
mStateMachine.isDisconnected(), mUntrustedConnectionAllowed);
mLatestCandidates = candidates;
mLatestCandidatesTimestampMs = mClock.getElapsedSinceBootMillis();
if (mDeviceMobilityState == WifiManager.DEVICE_MOBILITY_STATE_HIGH_MVMT
&& mContext.getResources().getBoolean(
R.bool.config_wifiHighMovementNetworkSelectionOptimizationEnabled)) {
candidates = filterCandidatesHighMovement(candidates, listenerName, isFullScan);
}
WifiConfiguration candidate = mNetworkSelector.selectNetwork(candidates);
mLastNetworkSelectionTimeStamp = mClock.getElapsedSinceBootMillis();
mWifiLastResortWatchdog.updateAvailableNetworks(
mNetworkSelector.getConnectableScanDetails());
mWifiMetrics.countScanResults(scanDetails);
if (candidate != null) {
localLog(listenerName + ": WNS candidate-" + candidate.SSID);
connectToNetwork(candidate);
return true;
} else {
if (mWifiState == WIFI_STATE_DISCONNECTED) {
mOpenNetworkNotifier.handleScanResults(
mNetworkSelector.getFilteredScanDetailsForOpenUnsavedNetworks());
}
return false;
}
}
处理过程分析如下:
1. 更新 WifiChannelUtilization 统计信息;
2. 更新和释放 Block 的 ssid 列表信息;
3. 判断当前是否处理 transite 状态,如果是的话则不再进一步处理;
4. 开始进行 WiFi 网络选择处理过程:
① 通过 NetworkSelector 类的 getCandidatesFromScan 方法对扫描结果进行处理,获取 candidates 列表,类型为 WifiCandidates.Candidate;
② 更新 mLatestCandidates 为最新,并且记录其 timestamp 信息(mLatestCandidatesTimestampMs);
③ 如果设备处于高速移动(WifiManager.DEVICE_MOBILITY_STATE_HIGH_MVMT)且可以进行高速移动下的优化选择,则调用 filterCandidatesHighMovement 对获取到的 candidates 进行过滤;
④ 继续调用 NetworkSelector 的 selectNetwork 方法选择网络,结果为 WifiConfiguration 类型,同时更新选择时间戳;
⑤ 更新 WifiLastResortWatchdog 中记录的可用网络信息,用于更准确的网络模块重启操作;
⑥ 更新 WifiMetrics 信息;
⑦ 如果存在被选中的 candidates,则进行连接过程 connectToNetwork;
⑧ 否则如果当前处于 WIFI_STATE_DISCONNECTED 状态,则调用 OpenNetworkNotifier 的 handleScanResults 接口进行处理,主要是在扫描结果中选择网络推荐给应用进行连接;
这里最重要的是三个点:WifiMetrics 类相关方法和功能的实现,NetworkSelector 的实现以及 connectToNetwork,也包括 WifiConfiguration 类作为参数传递给 connectToNetwork,下面分别进行分析。
WifiConnectivityManager 的启动和初始化
1. WifiConnectivityManager 对象在 ClientModeImpl 中创建,在其构造函数中通过 WifiInjector 的 makeWifiConnectivityManager 方法完成创建,在 ConnectModeState 状态进入时其 enter 方法中执行了 WifiConnectivityManager 对象的 setWifiEnabled,将 mWifiEnabled 状态修改为 true,并且调用了其 updateRunningState 方法,这里会执行 WifiConnectivityManager 的 start 或者 stop 方法,如果 mWifiEnabled 为 true 且 mAutoJoinEnabled 也为 true,则会启动 WifiConnectivityManager,如前面所分析的,注册对应的回调,在事件发生时可以进行处理。