美文网首页
Android之WIFI-扫描服务WifiScanningSer

Android之WIFI-扫描服务WifiScanningSer

作者: 锄禾豆 | 来源:发表于2022-02-17 09:44 被阅读0次

    简介

    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
    

    相关文章

      网友评论

          本文标题:Android之WIFI-扫描服务WifiScanningSer

          本文链接:https://www.haomeiwen.com/subject/gowqkrtx.html