简介
WifiScanningService用于自动扫描wlan
源码
7.1
服务端和客户端通信的案例
WifiScanner 与 WifiScanningService的通信--AsyncChannel
WifiScanner构造方法
public WifiScanner(Context context, IWifiScanner service, Looper looper) {
mContext = context;
mService = service;
Messenger messenger = null;
try {
messenger = mService.getMessenger();//获取了WifiScannerService的Handler
} 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);//建立起通信
}
详细分析
1.WifiScanningService开机启动
com.android.server.SystemServer
mSystemServiceManager.startService(
"com.android.server.wifi.scanner.WifiScanningService");
2.WifiScanningService。其实现类为WifiScanningServiceImpl
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);
}
@Override
public void onBootPhase(int phase) {
if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
Log.i(TAG, "Starting " + Context.WIFI_SCANNING_SERVICE);
mImpl.startService();
}
}
}
3.实现类分析:WifiScanningServiceImpl
1)adb查看:adb shell dumpsys wifiscanner
2)com.android.server.wifi.scanner.WifiScanningServiceImpl
public void startService() {
mClientHandler = new ClientHandler(mLooper);
mBackgroundScanStateMachine = new WifiBackgroundScanStateMachine(mLooper);
mWifiChangeStateMachine = new WifiChangeStateMachine(mLooper);
mSingleScanStateMachine = new WifiSingleScanStateMachine(mLooper);
mPnoScanStateMachine = new WifiPnoScanStateMachine(mLooper);
mContext.registerReceiver(
new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
int state = intent.getIntExtra(
WifiManager.EXTRA_SCAN_AVAILABLE, WifiManager.WIFI_STATE_DISABLED);
if (DBG) localLog("SCAN_AVAILABLE : " + state);
if (state == WifiManager.WIFI_STATE_ENABLED) {
mBackgroundScanStateMachine.sendMessage(CMD_DRIVER_LOADED);
mSingleScanStateMachine.sendMessage(CMD_DRIVER_LOADED);
mPnoScanStateMachine.sendMessage(CMD_DRIVER_LOADED);
} else if (state == WifiManager.WIFI_STATE_DISABLED) {
mBackgroundScanStateMachine.sendMessage(CMD_DRIVER_UNLOADED);
mSingleScanStateMachine.sendMessage(CMD_DRIVER_UNLOADED);
mPnoScanStateMachine.sendMessage(CMD_DRIVER_UNLOADED);
}
}
}, new IntentFilter(WifiManager.WIFI_SCAN_AVAILABLE));
mBackgroundScanStateMachine.start();
mWifiChangeStateMachine.start();
mSingleScanStateMachine.start();
mPnoScanStateMachine.start();
}
3)状态的改变通过监听广播WifiManager.WIFI_SCAN_AVAILABLE(wifi_scan_available)
注:
广播的状态跟WifiStateMachine.DriverStartedState绑定在一起
final Intent intent = new Intent(WifiManager.WIFI_SCAN_AVAILABLE);
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
intent.putExtra(WifiManager.EXTRA_SCAN_AVAILABLE, WIFI_STATE_ENABLED);
mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
4.具体分析广播触发导致的业务分发。以打开wifi为例
当接受到信息为WifiManager.WIFI_STATE_ENABLED时,处理如下:
单独从WifiSingleScanStateMachine状态机说起:
1)状态4:
DefaultState --- DriverStartedState --- IdleState
--- ScanningState
2)当接收到广播(打开wifi发送的广播)所带值为WifiManager.WIFI_STATE_ENABLED
mSingleScanStateMachine.sendMessage(CMD_DRIVER_LOADED);
a.默认初始状态为DefaultState,处理消息CMD_DRIVER_LOADED
WifiScanningServiceImpl.SingleScanStateMachine.DefaultState
class DefaultState extends State {
······
@Override
public boolean processMessage(Message msg) {
switch (msg.what) {
case CMD_DRIVER_LOADED:
transitionTo(mIdleState);//处理消息时,转化到新的状态
return HANDLED;
······
}
}
}
1)transitionTo(mIdleState)
先退后进。
退:默认DefaultState,无可退
进:DriverStartedState.enter --> IdleState.enter
class IdleState extends State {
@Override
public void enter() {
tryToStartNewScan();//执行扫描
}
···
}
void tryToStartNewScan() {
······
if (mScannerImpl.startSingleScan(settings, this)) {//调用mScannerImpl,执行扫描动作。mScannerImpl = mScannerImplFactory.create(mContext, mLooper, mClock);即SupplicantWifiScannerImpl
······
transitionTo(mScanningState);//执行成功,则切换状态
} else {
······
}
}
此方法分两部分分析:
11)第一部分:mScannerImpl.startSingleScan(settings, this)
SupplicantWifiScannerImpl
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) {
······
if ((newScanSettings.backgroundScanActive || newScanSettings.singleScanActive)
&& !allFreqs.isEmpty()) {
······
boolean success = mWifiNative.scan(freqs, hiddenNetworkIdSet);//WifiNative是跟wpa_supplicant的接口
if (success) {
······
} else {
······
}
} else if (isHwPnoScanRequired()) {
····
}
}
}
com.android.server.wifi.WifiNative
scan --> scanWithParams --> doBooleanCommand --> doBooleanCommandNative
private boolean scanWithParams(String freqList, String hiddenNetworkIdList) {
StringBuilder scanCommand = new StringBuilder();
scanCommand.append("SCAN TYPE=ONLY");//可关注此日志。TAG:WifiNative-wlan0, SCAN TYPE=
if (freqList != null) {
scanCommand.append(" freq=" + freqList);
}
if (hiddenNetworkIdList != null) {
scanCommand.append(" scan_id=" + hiddenNetworkIdList);
}
return doBooleanCommand(scanCommand.toString());
}
com_android_server_wifi_WifiNative.cpp
android_net_wifi_doBooleanCommand --> doBooleanCommand --> doCommand
wifi.c(hardware/libhardware_legacy/wifi/wifi.c)
wifi_command --> wifi_send_command --> wpa_ctrl_request
wpa_supplicant
wpa_ctrl_request
至此,wpa_supplicant扫描业务已经分析结束,问题:扫描所得的结果,怎么被扫描服务获取呢?
我们知道WifiMonitor是用来监听wpa_supplicant数据改变,而其他对象需要被WifiMonitor通知,则要调用WifiMonitor.registerHandler。
SupplicantWifiScannerImpl调用mWifiNative.scan,那是不是SupplicantWifiScannerImpl有WifiMonitor的registerHandler?
com.android.server.wifi.scanner.SupplicantWifiScannerImpl
public SupplicantWifiScannerImpl(Context context, WifiNative wifiNative,
ChannelHelper channelHelper, Looper looper, Clock clock) {
······
mEventHandler = new Handler(looper, this);
······
WifiMonitor.getInstance().registerHandler(mWifiNative.getInterfaceName(),
WifiMonitor.SCAN_FAILED_EVENT, mEventHandler);
WifiMonitor.getInstance().registerHandler(mWifiNative.getInterfaceName(),
WifiMonitor.SCAN_RESULTS_EVENT, mEventHandler);
}
具体WifiMonitor怎么监听怎么分发机制,这里我们先不提,可关注:WifiService之WifiMonitor深入分析。
WifiMonitor.SCAN_RESULTS_EVENT代表扫描所得的结果的通道
public boolean handleMessage(Message msg) {
switch(msg.what) {
······
case WifiMonitor.SCAN_RESULTS_EVENT:
mAlarmManager.cancel(mScanTimeoutListener);
pollLatestScanData();//拉取最新的wifi列表数据
processPendingScans();
break;
default:
// ignore unknown event
}
return true;
}
private void pollLatestScanData() {
synchronized (mSettingsLock) {
if (mLastScanSettings == null) {
// got a scan before we started scanning or after scan was canceled
return;
}
if (DBG) Log.d(TAG, "Polling scan data for scan: " + mLastScanSettings.scanId);
ArrayList<ScanDetail> nativeResults = mWifiNative.getScanResults();//从wpa_supplicant拉取数据
······
if (mLastScanSettings.backgroundScanActive) {
·······
}
if (mLastScanSettings.singleScanActive
&& mLastScanSettings.singleScanEventHandler != null) {
······
mLastScanSettings.singleScanEventHandler
.onScanStatus(WifiNative.WIFI_SCAN_RESULTS_AVAILABLE);//通知WifiScanningServiceImpl.WifiSingleScanStateMachine
}
if (mLastScanSettings.hwPnoScanActive
&& mLastScanSettings.pnoScanEventHandler != null) {
······
}
mLastScanSettings = null;
}
}
此方法分两部分分析:
111)mWifiNative.getScanResults()
com.android.server.wifi.WifiNative
getScanResults --> getRawScanResults --> doStringCommandWithoutLogging --> doStringCommandNative
private String getRawScanResults(String range) {
return doStringCommandWithoutLogging("BSS RANGE=" + range + " MASK=0x29d87");////可关注此日志。TAG:WifiNative-wlan0, BSS RANGE=
}
com_android_server_wifi_WifiNative.cpp
android_net_wifi_doStringCommand --> doStringCommand --> doCommand
wifi.c(hardware/libhardware_legacy/wifi/wifi.c)
wifi_command --> wifi_send_command --> wpa_ctrl_request
wpa_supplicant
wpa_ctrl_request
112)mLastScanSettings.singleScanEventHandler
.onScanStatus(WifiNative.WIFI_SCAN_RESULTS_AVAILABLE)
com.android.server.wifi.scanner.WifiScanningServiceImpl
public void onScanStatus(int event) {
if (DBG) localLog("onScanStatus event received, event=" + event);
switch(event) {
case WifiNative.WIFI_SCAN_RESULTS_AVAILABLE:
sendMessage(CMD_SCAN_RESULTS_AVAILABLE);//状态机的业务分发
break;
······
}
}
此时分析12)价值来了
12)第二部分:transitionTo(mScanningState)
com.android.server.wifi.scanner.WifiScanningServiceImpl
先退后进。
退:无,因为ScanningState和IdleState共同一DriverStartedState
进:ScanningState.enter
class ScanningState extends State {
private WorkSource mScanWorkSource;
@Override
public void enter() {
······
}
@Override
public void exit() {
······
}
@Override
public boolean processMessage(Message msg) {
switch (msg.what) {
case CMD_SCAN_RESULTS_AVAILABLE:
mWifiMetrics.incrementScanReturnEntry(
WifiMetricsProto.WifiLog.SCAN_SUCCESS,
mActiveScans.size());
reportScanResults(mScannerImpl.getLatestSingleScanResults());//把结果通知出去
mActiveScans.clear();
transitionTo(mIdleState);
return HANDLED;
······
}
}
}
结合112)可知,最后来到processMessage的CMD_SCAN_RESULTS_AVAILABLE
void reportScanResults(ScanData results) {
······
WifiScanner.ParcelableScanData parcelableAllResults =
new WifiScanner.ParcelableScanData(allResults);
for (RequestInfo<Void> entry : mSingleScanListeners) {
logCallback("singleScanResults", entry.clientInfo, entry.handlerId,
describeForLog(allResults));
entry.reportEvent(WifiScanner.CMD_SCAN_RESULT, 0, parcelableAllResults);
}
}
WifiScanningServiceImpl.ExternalClientInfo.reportEvent
public void reportEvent(int what, int arg1, int arg2, Object obj) {
if (!mDisconnected) {
mChannel.sendMessage(what, arg1, arg2, obj);//把数据发送给客户端
}
}
这里说完了扫描的服务的处理业务。接下来的关键在于客户端的业务处理
5.客户端怎么监听服务端数据的变化。以自动连接wifi为例
1)mSingleScanListeners为客户端的监听者。它是怎么收集监听者呢?
com.android.server.wifi.scanner.WifiScanningServiceImpl
弄清楚回到客户端(WifiScanner)与服务端(WifiScanningServiceImpl)通信的具体方法AsyncChannel,就明白:
private class ClientHandler extends Handler {
ClientHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
······
switch (msg.what) {
case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION: {//客户端和服务端建立连接时,进行的初始化操作
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 WifiScanner.CMD_REGISTER_SCAN_LISTENER:
logScanRequest("registerScanListener", ci, msg.arg2, null, null, null);
mSingleScanListeners.addRequest(ci, msg.arg2, null, null);//客户端怎么处理呢?
replySucceeded(msg);
break;
······
}
}
2)客户端WifiScanner怎么处理?
a.客户端监听
android.net.wifi.WifiScanner
private class ServiceHandler extends Handler {
ServiceHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
···
Object listener = getListener(msg.arg2);//这里获取监听对象。这里跟一般的监听方法不一样
···
switch (msg.what) {
···
case CMD_SCAN_RESULT :
if (DBG) Log.d(TAG, "CMD_SCAN_RESULT ");
((ScanListener) listener).onResults(
((ParcelableScanData) msg.obj).getResults());
break;
}
}
监听对象的来源?
因WifiConnectivityManager包裹了WifiScanner,我们先看WifiConnectivityManager
com.android.server.wifi.WifiConnectivityManager
public WifiConnectivityManager(Context context, WifiStateMachine stateMachine,
WifiScanner scanner, WifiConfigManager configManager, WifiInfo wifiInfo,
WifiQualifiedNetworkSelector qualifiedNetworkSelector,
WifiInjector wifiInjector, Looper looper, boolean enable) {
mStateMachine = stateMachine;
mScanner = scanner;
·······
// Register for all single scan results
mScanner.registerScanListener(mAllSingleScanListener);//查看mAllSingleScanListener。客户端进行数据监听
·······
}
b.客户端对监听数据进行处理
private class AllSingleScanListener implements WifiScanner.ScanListener {
······
@Override
public void onResults(WifiScanner.ScanData[] results) {//数据回调处
······
boolean wasConnectAttempted = handleScanResults(mScanDetails, "AllSingleScanListener");//自动连接的具体方法
······
}
·······
}
private boolean handleScanResults(List<ScanDetail> scanDetails, String listenerName) {
localLog(listenerName + " onResults: start QNS");
WifiConfiguration candidate =
mQualifiedNetworkSelector.selectQualifiedNetwork(false,
mUntrustedConnectionAllowed, scanDetails,
mStateMachine.isLinkDebouncing(), mStateMachine.isConnected(),
mStateMachine.isDisconnected(),
mStateMachine.isSupplicantTransientState());//获取是否有可连接的网络。WifiQualifiedNetworkSelector涉及wifi评分机制。有兴趣的可自行分析
mWifiLastResortWatchdog.updateAvailableNetworks(
mQualifiedNetworkSelector.getFilteredScanDetails());
mWifiMetrics.countScanResults(scanDetails);
if (candidate != null) {//如果网络存在,则连接
localLog(listenerName + ": QNS candidate-" + candidate.SSID);
connectToNetwork(candidate);
return true;
} else {
return false;
}
}
private void connectToNetwork(WifiConfiguration candidate) {
······
if (currentConnectedNetwork != null
&& (currentConnectedNetwork.networkId == candidate.networkId
|| currentConnectedNetwork.isLinked(candidate))) {
localLog("connectToNetwork: Roaming from " + currentAssociationId + " to "
+ targetAssociationId);
mStateMachine.autoRoamToNetwork(candidate.networkId, scanResultCandidate);
} else {
localLog("connectToNetwork: Reconnect from " + currentAssociationId + " to "
+ targetAssociationId);
mStateMachine.autoConnectToNetwork(candidate.networkId, scanResultCandidate.BSSID);//调用WifiStateMachine的自动连接
}
}
com.android.server.wifi.WifiStateMachine
public void autoConnectToNetwork(int networkId, String bssid) {
Thread.dumpStack();
synchronized (mWifiReqCountLock) {
if (hasConnectionRequests()) {
sendMessage(CMD_AUTO_CONNECT, networkId, 0, bssid);//状态机开始处理
}
}
}
此时,WifiStateMachine处于DisconnectedState状态。
根据状态机处理业务逻辑,子状态无法处理,则父状态处理。
ConnectModeState
class ConnectModeState extends State {
@Override
public void enter() {
······
}
@Override
public void exit() {
······
}
@Override
public boolean processMessage(Message message) {
case CMD_AUTO_CONNECT:
······
/* Save the network config */
logd("CMD_AUTO_CONNECT will save config -> " + config.SSID
+ " nid=" + Integer.toString(netId));
result = mWifiConfigManager.saveNetwork(config, WifiConfiguration.UNKNOWN_UID);//保存网络状态
······
if (mWifiConfigManager.selectNetwork(config, /* updatePriorities = */ false,
lastConnectUid) && mWifiNative.reconnect()) {//选择网络并且重新连接
······
} else {
······
}
break;
}
}
问题:reconnect之后,怎么知道连接成功了呢?
关注WifiMonitor对wpa_supplicant的监听。结果为:WifiMonitor发送事件CTRL-EVENT-CONNECTED出来,转化为Message.what为NETWORK_CONNECTION_EVENT
问题:DisconnectedState怎么最后转化成了ConnectedState?
DisconnectedState先切换到状态mObtainingIpState,再从mObtainingIpState切换到ConnectedState
补充流程:
保存网络
mWifiConfigManager.saveNetwork(config, WifiConfiguration.UNKNOWN_UID);
com.android.server.wifi.WifiConfigManager
saveNetwork --> saveConfig --> mWifiConfigStore.saveConfig()
com.android.server.wifi.WifiConfigStore
saveConfig --> mWifiNative.saveConfig()
com.android.server.wifi.WifiNative
saveConfig --> doBooleanCommand --> doBooleanCommandNative
关注日志。TAG:WifiNative-wlan0 SAVE_CONFIG
选择网络
mWifiConfigManager.selectNetwork(config, /* updatePriorities = */ false,
lastConnectUid)
com.android.server.wifi.WifiConfigManager
selectNetwork --> selectNetworkWithoutBroadcast --> mWifiConfigStore.selectNetwork(
mConfiguredNetworks.getForCurrentUser(netId),
mConfiguredNetworks.valuesForCurrentUser())
com.android.server.wifi.WifiConfigStore
selectNetwork --> mWifiNative.selectNetwork(config.networkId)
com.android.server.wifi.WifiNative
selectNetwork --> doBooleanCommand --> doBooleanCommandNative
关注日志。TAG:WifiNative-wlan0 SELECT_NETWORK
重新连接
com.android.server.wifi.WifiNative
reconnect --> doBooleanCommand --> doBooleanCommandNative
关注日志。TAG:WifiNative-wlan0 RECONNECT
小结:
a.自动连接最后仍会回到WifiStateMachine的操作
b.WifiMonitor监听了wpa_supplicant的消息发送
总结
1.wifi扫描服务,作为系统服务,主要定时扫描wifi
2.为了更好的解耦客户端,同时,更好的服务客户端,采用了AsyncChannel双handler进程通信
3.客户端可以根据定时扫描的结果进行wifi自动连接,关键类:WifiConnectivityManager
客户端类:WifiScanner
网友评论