Android之WIFI-掃描服務(wù)WifiScanningService分析

簡(jiǎn)介

WifiScanningService用于自動(dòng)掃描wlan

源碼

7.1

服務(wù)端和客戶端通信的案例

WifiScanner 與 WifiScanningService的通信--AsyncChannel

WifiScanner構(gòu)造方法

    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);//建立起通信
    }

詳細(xì)分析
1.WifiScanningService開(kāi)機(jī)啟動(dòng)

com.android.server.SystemServer
    mSystemServiceManager.startService(
                            "com.android.server.wifi.scanner.WifiScanningService");

2.WifiScanningService狠半。其實(shí)現(xiàn)類(lèi)為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.實(shí)現(xiàn)類(lèi)分析: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)狀態(tài)的改變通過(guò)監(jiān)聽(tīng)廣播WifiManager.WIFI_SCAN_AVAILABLE(wifi_scan_available)
注:
廣播的狀態(tài)跟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.具體分析廣播觸發(fā)導(dǎo)致的業(yè)務(wù)分發(fā)。以打開(kāi)wifi為例

當(dāng)接受到信息為WifiManager.WIFI_STATE_ENABLED時(shí)缝左,處理如下:
單獨(dú)從WifiSingleScanStateMachine狀態(tài)機(jī)說(shuō)起:

1)狀態(tài)4:

DefaultState  --- DriverStartedState  --- IdleState
                                      --- ScanningState

2)當(dāng)接收到廣播(打開(kāi)wifi發(fā)送的廣播)所帶值為WifiManager.WIFI_STATE_ENABLED

mSingleScanStateMachine.sendMessage(CMD_DRIVER_LOADED);

a.默認(rèn)初始狀態(tài)為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);//處理消息時(shí)卖局,轉(zhuǎn)化到新的狀態(tài)
                        return HANDLED;
                    ······
                }

            }
        }
        1)transitionTo(mIdleState)
        先退后進(jìn)。
        退:默認(rèn)DefaultState双霍,無(wú)可退
        進(jìn):DriverStartedState.enter  --> IdleState.enter
        
        class IdleState extends State {
            @Override
            public void enter() {
                tryToStartNewScan();//執(zhí)行掃描
            }
            ···
        }
        
        void tryToStartNewScan() {
            ······
            if (mScannerImpl.startSingleScan(settings, this)) {//調(diào)用mScannerImpl砚偶,執(zhí)行掃描動(dòng)作。mScannerImpl = mScannerImplFactory.create(mContext, mLooper, mClock);即SupplicantWifiScannerImpl
                ······
                transitionTo(mScanningState);//執(zhí)行成功洒闸,則切換狀態(tài)
            } 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();//真正處理的掃描業(yè)務(wù)
            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");//可關(guān)注此日志染坯。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掃描業(yè)務(wù)已經(jīng)分析結(jié)束丘逸,問(wèn)題:掃描所得的結(jié)果单鹿,怎么被掃描服務(wù)獲取呢?
    我們知道WifiMonitor是用來(lái)監(jiān)聽(tīng)wpa_supplicant數(shù)據(jù)改變深纲,而其他對(duì)象需要被WifiMonitor通知仲锄,則要調(diào)用WifiMonitor.registerHandler劲妙。
    SupplicantWifiScannerImpl調(diào)用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怎么監(jiān)聽(tīng)怎么分發(fā)機(jī)制是趴,這里我們先不提,可關(guān)注:WifiService之WifiMonitor深入分析澄惊。
    
    WifiMonitor.SCAN_RESULTS_EVENT代表掃描所得的結(jié)果的通道
    public boolean handleMessage(Message msg) {
        switch(msg.what) {
            ······
            case WifiMonitor.SCAN_RESULTS_EVENT:
                mAlarmManager.cancel(mScanTimeoutListener);
                pollLatestScanData();//拉取最新的wifi列表數(shù)據(jù)
                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拉取數(shù)據(jù)
            ······

            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");////可關(guān)注此日志唆途。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);//狀態(tài)機(jī)的業(yè)務(wù)分發(fā)
                    break;
                ······
            }
        }
        此時(shí)分析12)價(jià)值來(lái)了
12)第二部分:transitionTo(mScanningState)
    com.android.server.wifi.scanner.WifiScanningServiceImpl
    先退后進(jìn)。
    退:無(wú)掸驱,因?yàn)镾canningState和IdleState共同一DriverStartedState
    進(jìn):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());//把結(jié)果通知出去
                        mActiveScans.clear();
                        transitionTo(mIdleState);
                        return HANDLED;
                    ······
                }
            }
        }
        結(jié)合112)可知肛搬,最后來(lái)到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);//把數(shù)據(jù)發(fā)送給客戶端
            }
        }
        這里說(shuō)完了掃描的服務(wù)的處理業(yè)務(wù)。接下來(lái)的關(guān)鍵在于客戶端的業(yè)務(wù)處理

5.客戶端怎么監(jiān)聽(tīng)服務(wù)端數(shù)據(jù)的變化毕贼。以自動(dòng)連接wifi為例
1)mSingleScanListeners為客戶端的監(jiān)聽(tīng)者温赔。它是怎么收集監(jiān)聽(tīng)者呢?

com.android.server.wifi.scanner.WifiScanningServiceImpl
弄清楚回到客戶端(WifiScanner)與服務(wù)端(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: {//客戶端和服務(wù)端建立連接時(shí)陶贼,進(jìn)行的初始化操作
                    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.客戶端監(jiān)聽(tīng)

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);//這里獲取監(jiān)聽(tīng)對(duì)象拜秧。這里跟一般的監(jiān)聽(tīng)方法不一樣
            ···
            switch (msg.what) {
                ···
                case CMD_SCAN_RESULT :
                    if (DBG) Log.d(TAG, "CMD_SCAN_RESULT ");
                    ((ScanListener) listener).onResults(
                            ((ParcelableScanData) msg.obj).getResults());
                    break;
            
        }
    }

監(jiān)聽(tīng)對(duì)象的來(lái)源?
因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章郁⊥鞯客戶端進(jìn)行數(shù)據(jù)監(jiān)聽(tīng)
        ·······
    }

b.客戶端對(duì)監(jiān)聽(tīng)數(shù)據(jù)進(jìn)行處理

    private class AllSingleScanListener implements WifiScanner.ScanListener {
        ······
        @Override
        public void onResults(WifiScanner.ScanData[] results) {//數(shù)據(jù)回調(diào)處
            ······
            boolean wasConnectAttempted = handleScanResults(mScanDetails, "AllSingleScanListener");//自動(dòng)連接的具體方法
            ······
        }
        ·······
    }
    
    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());//獲取是否有可連接的網(wǎng)絡(luò)。WifiQualifiedNetworkSelector涉及wifi評(píng)分機(jī)制暖庄。有興趣的可自行分析
        mWifiLastResortWatchdog.updateAvailableNetworks(
                mQualifiedNetworkSelector.getFilteredScanDetails());
        mWifiMetrics.countScanResults(scanDetails);
        if (candidate != null) {//如果網(wǎng)絡(luò)存在聊替,則連接
            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);//調(diào)用WifiStateMachine的自動(dòng)連接
        }
    }
    
    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);//狀態(tài)機(jī)開(kāi)始處理
            }
        }
    }
    此時(shí),WifiStateMachine處于DisconnectedState狀態(tài)培廓。
    
    根據(jù)狀態(tài)機(jī)處理業(yè)務(wù)邏輯惹悄,子狀態(tài)無(wú)法處理,則父狀態(tài)處理肩钠。
    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);//保存網(wǎng)絡(luò)狀態(tài)
                    ······
                    if (mWifiConfigManager.selectNetwork(config, /* updatePriorities = */ false,
                            lastConnectUid) && mWifiNative.reconnect()) {//選擇網(wǎng)絡(luò)并且重新連接
                        ······
                    } else {
                        ······
                    }
                    break;  
        }
    }
    
    問(wèn)題:reconnect之后俘侠,怎么知道連接成功了呢?
    關(guān)注WifiMonitor對(duì)wpa_supplicant的監(jiān)聽(tīng)蔬将。結(jié)果為:WifiMonitor發(fā)送事件CTRL-EVENT-CONNECTED出來(lái),轉(zhuǎn)化為Message.what為NETWORK_CONNECTION_EVENT
    
    問(wèn)題:DisconnectedState怎么最后轉(zhuǎn)化成了ConnectedState央星?
    DisconnectedState先切換到狀態(tài)mObtainingIpState霞怀,再?gòu)膍ObtainingIpState切換到ConnectedState
    
    補(bǔ)充流程:
    保存網(wǎng)絡(luò)
    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
    關(guān)注日志。TAG:WifiNative-wlan0 SAVE_CONFIG
    
    選擇網(wǎng)絡(luò)
    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
    關(guān)注日志莉给。TAG:WifiNative-wlan0 SELECT_NETWORK
    
    重新連接
    com.android.server.wifi.WifiNative
    reconnect --> doBooleanCommand --> doBooleanCommandNative
    關(guān)注日志毙石。TAG:WifiNative-wlan0 RECONNECT
    
    小結(jié):
    a.自動(dòng)連接最后仍會(huì)回到WifiStateMachine的操作
    b.WifiMonitor監(jiān)聽(tīng)了wpa_supplicant的消息發(fā)送

總結(jié)

1.wifi掃描服務(wù)廉沮,作為系統(tǒng)服務(wù),主要定時(shí)掃描wifi
2.為了更好的解耦客戶端徐矩,同時(shí)滞时,更好的服務(wù)客戶端,采用了AsyncChannel雙handler進(jìn)程通信
3.客戶端可以根據(jù)定時(shí)掃描的結(jié)果進(jìn)行wifi自動(dòng)連接滤灯,關(guān)鍵類(lèi):WifiConnectivityManager
客戶端類(lèi):WifiScanner
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末坪稽,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子鳞骤,更是在濱河造成了極大的恐慌窒百,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,204評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件豫尽,死亡現(xiàn)場(chǎng)離奇詭異篙梢,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)美旧,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,091評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)渤滞,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人榴嗅,你說(shuō)我怎么就攤上這事妄呕。” “怎么了录肯?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,548評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵趴腋,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我论咏,道長(zhǎng)优炬,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,657評(píng)論 1 293
  • 正文 為了忘掉前任厅贪,我火速辦了婚禮蠢护,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘养涮。我一直安慰自己葵硕,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,689評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布贯吓。 她就那樣靜靜地躺著懈凹,像睡著了一般。 火紅的嫁衣襯著肌膚如雪悄谐。 梳的紋絲不亂的頭發(fā)上介评,一...
    開(kāi)封第一講書(shū)人閱讀 51,554評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼们陆。 笑死寒瓦,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的坪仇。 我是一名探鬼主播杂腰,決...
    沈念sama閱讀 40,302評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼椅文!你這毒婦竟也來(lái)了喂很?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,216評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤雾袱,失蹤者是張志新(化名)和其女友劉穎恤筛,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體芹橡,經(jīng)...
    沈念sama閱讀 45,661評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡毒坛,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,851評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了林说。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片煎殷。...
    茶點(diǎn)故事閱讀 39,977評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖腿箩,靈堂內(nèi)的尸體忽然破棺而出豪直,到底是詐尸還是另有隱情,我是刑警寧澤珠移,帶...
    沈念sama閱讀 35,697評(píng)論 5 347
  • 正文 年R本政府宣布弓乙,位于F島的核電站,受9級(jí)特大地震影響钧惧,放射性物質(zhì)發(fā)生泄漏暇韧。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,306評(píng)論 3 330
  • 文/蒙蒙 一浓瞪、第九天 我趴在偏房一處隱蔽的房頂上張望懈玻。 院中可真熱鬧,春花似錦乾颁、人聲如沸涂乌。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,898評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)湾盒。三九已至,卻和暖如春诅妹,著一層夾襖步出監(jiān)牢的瞬間历涝,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,019評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留荧库,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,138評(píng)論 3 370
  • 正文 我出身青樓赵刑,卻偏偏與公主長(zhǎng)得像分衫,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子般此,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,927評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容