写这篇博文前,参考了不少优秀的博客,对照着Android 11的源码,做了一次不大精细的走读
本文源自WifiConnectivityManager 管理扫描
WifiConnectivityManager 通过 WifiScanner.java 中 WifiScanner 类的 registerScanListener 方法注册 Scan 结果的回调监听句柄,实际上内部通过 AsyncChannel 向 WifiScanningService 层发送了 CMD_REGISTER_SCAN_LISTENER 消息:
/**
* 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();
......
}
// All single scan results listener.
//
// Note: This is the listener for all the available single scan results,
// including the ones initiated by WifiConnectivityManager and
// other modules.
private class AllSingleScanListener implements WifiScanner.ScanListener {...}
WifiScanner 源码见 /frameworks/base/wifi/java/android/net/wifi/WifiScanner.java
/**
* 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);
}
mAllSingleScanListener 为 AllSingleScanListener 类对象,实现了 WifiScanner 的 ScanListener 接口类,在服务端进行 reportScanResults 等操作时对应的方法被调用用来处理回调事件
class WifiScanningService 定义在 WifiScanningService.java 文件中,其实际的实现在 WifiScanningServiceImpl 类中,向系统注册并提供 WIFI_SCANNING_SERVICE 服务:
服务的实际注册发生在 WifiFrameworkInitializer 中的 registerServiceWrappers 方法中,与 WIFI_SERVICE 等一起注册。客户端则在 WifiScanner 类中实现,在文件 WifiScanner.java 文件中
接下来看在服务端 WifiScanningServiceImpl 中的处理过程:
-
消息处理发生在 ClientHandler 内部类中,其 handleMessage 接口进行处理,实际上就是将对应的请求信息添加到 mSingleScanListeners 链中,其类型为 RequestList<>,添加方法为 addRequest,也是内部私有实现的类;
-
消息回送发生在 reportFullScanResult 和 reportScanResults 接口中,通知消息有 CMD_SCAN_RESULT,CMD_SINGLE_SCAN_COMPLETED 和 CMD_FULL_SCAN_RESULT 三种;
WifiConnectivityManager 类中通过 retrieveWifiScanner 方法创建 WifiScanner 对象 mScanner,使其指向 WIFI_SCANNING_SERVICE 服务,同时向服务端注册 Scan 监听者
/**
* 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();
}
}
}
回到 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;
}
}
具体的处理过程分析如下:
-
判断 WiFi 开启(mWifiEnabled),并且打开了自动链接配置(mAutoJoinEnabled),否则退出;
-
确定是否 FullBandScan 的结果(isFullBandScanResults);
-
判断是否需要等带 FullBandScan 的结果,并根据第 2 步判断的结果来确定是否继续处理或者等待;
-
更新 mWifiMetrics 的相关信息,关于 WifiMetrics 后面再分析;
-
记录一些 Log 信息;
-
最重要的 handleScanResults 登场,实际的扫描结果处理发生在该接口中,稍后详细分析该函数实现;
-
处理之后清楚扫描的结果内容;
-
继续更新 mWifiMetrics 相关的信息;
-
查询当前的扫描状态,并进行相应的更新以及 mWifiMetrics 处理,如果链接过程并未进行,则触发 WiFi 的连接过程( startConnectivityScan ,并且立即连接 SCAN_IMMEIDATELY);
/**
* 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);
//OS : Modify by chenyang 20200805 start
boolean isGameMode = Settings.Global.getInt(
mContext.getContentResolver(),
"transsion_game_mode", 0) == 1;
isGameMode = isGameMode && (Settings.Global.getInt(
mContext.getContentResolver(),
"os_change_network_protection", 0) == 1) && isMobileConnected();
if (candidate != null && !isGameMode) {
//OS : Modify by chenyang 20200805 end
localLog(listenerName + ": WNS candidate-" + candidate.SSID);
connectToNetwork(candidate);
return true;
} else {
if (mWifiState == WIFI_STATE_DISCONNECTED) {
mOpenNetworkNotifier.handleScanResults(
mNetworkSelector.getFilteredScanDetailsForOpenUnsavedNetworks());
}
return false;
}
}
处理过程分析如下:
-
更新 WifiChannelUtilization 统计信息;
-
更新和释放 Block 的 ssid 列表信息;
-
判断当前是否处理 transient 状态,如果是的话则不再进一步处理;
-
开始进行 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,下面分别进行分析。