Android6.0 打开wifi

版权声明:本文为博主原创文章,未经博主允许不得转载。https://blog.csdn.net/huangweiqing80/article/details/82702911
二、向wpa_supplicant发送命令
想象一下在应用程序我们怎么连接wifi:
1打开和关闭wifi
WifiManager wifi = (WifiManager) getSystemService(Context.WIFI_SERVICE);
wifi.setWifiEnabled(true);
2扫描附近热点
startScan();之后,接受WifiManager.SCAN_RESULTS_AVAILABLE_ACTION的广播会触发,在这个广播中调用getScanResults()方法可以获得一个List,它里面的每一个条目就是一个可连接的热点。
wifi.startScan();
results = wifi.getScanResults();
一般我们可能都需要做这两步吧,那么这两步会导致wifi状态机做怎么样的改变呢?
首先,用一张图来概括这个过程,然后大家可以顺着这个图的思路分析代码:
这里写图片描述

2 打开wifi
应用程序中调用
WifiManager wifi = (WifiManager) getSystemService(Context.WIFI_SERVICE);
wifi.setWifiEnabled(true);
首先从setWifiEnabled开始,wifi是一个WifiServiceImpl的客户端WifiManager wifi = (WifiManager) getSystemService(Context.WIFI_SERVICE); ,它会通过binder和WifiServiceImpl的实例交互,也就是我们在WifiService中通过addService方法向系统注册的mImpl对象,忘记的可以回头看看前面。
frameworks/base/wifi/java/android/net/wifi/WifiManager.java

    public boolean setWifiEnabled(boolean enabled) {
        try {
            return mService.setWifiEnabled(enabled);
        } catch (RemoteException e) {
            return false;
        }
    }

最终调用的的是WifiServiceImpl中的setWifiEnabled方法:
frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiServiceImpl.java

    public synchronized boolean setWifiEnabled(boolean enable) {
        enforceChangePermission();
        Slog.d(TAG, "setWifiEnabled: " + enable + " pid=" + Binder.getCallingPid()
                    + ", uid=" + Binder.getCallingUid());
        if (DBG) {
            Slog.e(TAG, "Invoking mWifiStateMachine.setWifiEnabled\n");
        }

        /*
        * Caller might not have WRITE_SECURE_SETTINGS,
        * only CHANGE_WIFI_STATE is enforced
        */

        long ident = Binder.clearCallingIdentity();
        try {
            if (! mSettingsStore.handleWifiToggled(enable)) {
                // Nothing to do if wifi cannot be toggled
                return true;
            }
        } finally {
            Binder.restoreCallingIdentity(ident);
        }

        mWifiController.sendMessage(CMD_WIFI_TOGGLED);
        return true;
    }

这个方法首先要使用mSettingsStore.handleWifiToggled(enable)来判断wifi状态是否可以切换,不能切换就直接返回。如果wifi状态可以切换,那么接下来会使用mWifiController.sendMessage(CMD_WIFI_TOGGLED);来给mWifiController状态机发送一条消息,我们说过mWifiController状态机控制wifi设备的开关灯状态,由此开来这句话是对的哈。
WifiController的processMessage方法会被调用,但是我们还不知道是调用WifiController状态机中哪个状态的processMessage。下面我们先来看一下WifiController的构造函数中添加的状态和初始状态。

 WifiController(Context context, WifiServiceImpl service, Looper looper) {
        super(TAG, looper);
        mContext = context;
        mWifiStateMachine = service.mWifiStateMachine;
        mSettingsStore = service.mSettingsStore;
        mLocks = service.mLocks;

        mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
        Intent idleIntent = new Intent(ACTION_DEVICE_IDLE, null);
        mIdleIntent = PendingIntent.getBroadcast(mContext, IDLE_REQUEST, idleIntent, 0);

        addState(mDefaultState);
            addState(mApStaDisabledState, mDefaultState);
            addState(mStaEnabledState, mDefaultState);
                addState(mDeviceActiveState, mStaEnabledState);
                addState(mDeviceInactiveState, mStaEnabledState);
                    addState(mScanOnlyLockHeldState, mDeviceInactiveState);
                    addState(mFullLockHeldState, mDeviceInactiveState);
                    addState(mFullHighPerfLockHeldState, mDeviceInactiveState);
                    addState(mNoLockHeldState, mDeviceInactiveState);
            addState(mStaDisabledWithScanState, mDefaultState);
            addState(mApEnabledState, mDefaultState);
            addState(mEcmState, mDefaultState);

        boolean isAirplaneModeOn = mSettingsStore.isAirplaneModeOn();
        boolean isWifiEnabled = mSettingsStore.isWifiToggleEnabled();
        boolean isScanningAlwaysAvailable = mSettingsStore.isScanAlwaysAvailable();

        log("isAirplaneModeOn = " + isAirplaneModeOn +
                ", isWifiEnabled = " + isWifiEnabled +
                ", isScanningAvailable = " + isScanningAlwaysAvailable);

        if (isScanningAlwaysAvailable) {
            setInitialState(mStaDisabledWithScanState);
        } else {
            setInitialState(mApStaDisabledState);
        }

我们刚开始打开wifi,WifiController状态机刚运行,所以此时状态机的状态一定是初始状态,可以看到我们的初始状态是mApStaDisabledState,所以下面我们来看一下WifiController的mApStaDisabledState的processMessage方法

    class ApStaDisabledState extends State {
        private int mDeferredEnableSerialNumber = 0;
        private boolean mHaveDeferredEnable = false;
        private long mDisabledTimestamp;

        @Override
        public void enter() {
            mWifiStateMachine.setSupplicantRunning(false);
            // Supplicant can't restart right away, so not the time we switched off
            mDisabledTimestamp = SystemClock.elapsedRealtime();
            mDeferredEnableSerialNumber++;
            mHaveDeferredEnable = false;
            mWifiStateMachine.clearANQPCache();
        }
        @Override
        public boolean processMessage(Message msg) {
            switch (msg.what) {
                case CMD_WIFI_TOGGLED:
                case CMD_AIRPLANE_TOGGLED:
                    if (mSettingsStore.isWifiToggleEnabled()) {
                        if (doDeferEnable(msg)) {
                            if (mHaveDeferredEnable) {
                                //  have 2 toggles now, inc serial number an ignore both
                                mDeferredEnableSerialNumber++;
                            }
                            mHaveDeferredEnable = !mHaveDeferredEnable;
                            break;
                        }
                        if (mDeviceIdle == false) {
                            transitionTo(mDeviceActiveState);
                        } else {
                            checkLocksAndTransitionWhenDeviceIdle();
                        }
                    } else if (mSettingsStore.isScanAlwaysAvailable()) {
                        transitionTo(mStaDisabledWithScanState);
                    }
                    break;
    ....

上面主要做了如下两个操作:

1.若500毫秒内重复打开或者关闭wifi不做处理
2.将当前WifiController中的ApStaDisabledState状态转换到DeviceActiveState
DeviceActiveState为StaEnabledState的子状态,所以会先调用父状态的enter()函数,然后调用子状态的enter()函数。
2.1DeviceActiveState
但是我们这里先来看看最后调到的DeviceActiveState的enter()函数,为什么先看DeviceActiveState呢,因为DeviceActiveState的enter()函数没干什么
frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiController.java

/* Parent: StaEnabledState */  
class DeviceActiveState extends State {  
    @Override  
    public void enter() {  
        mWifiStateMachine.setOperationalMode(WifiStateMachine.CONNECT_MODE);  
        mWifiStateMachine.setDriverStart(true);  
        mWifiStateMachine.setHighPerfModeEnabled(false);
    }
    ...  
} 

2.1.1.setOperationalMode 这里设置模式 可扫描、可连接。
STA的3个操作状态:CONNECT_MODE,SCAN_ONLY_MODE,SCAN_ONLY_WIFI_OFF_MODE
*在CONNECT_MODE中,STA可以扫描并连接到接入点
*在SCAN_ONLY_MODE中,STA只能扫描接入点
*在SCAN_ONLY_WIFI_OFF_MODE中,STA只能扫描(wifi关闭状态下)

2.1.2.setDriverStart(true) 发送CMD_START_DRIVER 消息。该消息在DriverStartedState中处理。

case CMD_START_DRIVER:
    if (mInDelayedStop) {
        mInDelayedStop = false;
        mDelayedStopCounter++;
        mAlarmManager.cancel(mDriverStopIntent);
        if (DBG) log("Delayed stop ignored due to start");
        if (mOperationalMode == CONNECT_MODE) {
            mWifiConfigStore.enableAllNetworks();
        }
    }
    break;

如果正在延时关闭驱动,则取消关闭。并将保存的wifi都Enable。

2.1.3.setHighPerfModeEnabled暂时不清楚什么情况。

2.2 StaEnabledState
再来看看DeviceActiveState父状态StaEnabledState的enter()函数:

class StaEnabledState extends State {  
    @Override  
    public void enter() {  
        mWifiStateMachine.setSupplicantRunning(true);  
    }  
    ...  
    }  
}  

调用mWifiStateMachine.setSupplicantRunning(true);

    /**
     * TODO: doc
     */
    public void setSupplicantRunning(boolean enable) {
        if (enable) {
            sendMessage(CMD_START_SUPPLICANT);
        } else {
            sendMessage(CMD_STOP_SUPPLICANT);
        }
    }

mWifiStateMachine.setSupplicantRunning(true),WifiStateMachine发送Message--CMD_STAET_SUPPLICANT。

WIfiStateMachine初始状态为InitialState
看看WIfiStateMachine的InitialState处理该消息
frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiStateMachine.java

class InitialState extends State {
    @Override
    public boolean processMessage(Message message) {
        switch (message.what) {
            case CMD_START_SUPPLICANT:
                //加载Wifi驱动
                if (mWifiNative.loadDriver()) {
                    try {//加载固件
                        mNwService.wifiFirmwareReload(mInterfaceName, "STA");
                    } catch (Exception e) {
                    }

                    try {
                        // A runtime crash can leave the interface up and
                        // this affects connectivity when supplicant starts up.
                        // Ensure interface is down before a supplicant start.
                        mNwService.setInterfaceDown(mInterfaceName);
                        // Set privacy extensions
                        mNwService.setInterfaceIpv6PrivacyExtensions(mInterfaceName, true);

                       // IPv6 is enabled only as long as access point is connected since:
                       // - IPv6 addresses and routes stick around after disconnection
                       // - kernel is unaware when connected and fails to start IPv6 negotiation
                       // - kernel can start autoconfiguration when 802.1x is not complete
                        mNwService.disableIpv6(mInterfaceName);
                    } catch (RemoteException re) {
                        loge("Unable to change interface settings: " + re);
                    } catch (IllegalStateException ie) {
                        loge("Unable to change interface settings: " + ie);
                    }

                   /* Stop a running supplicant after a runtime restart
                    * Avoids issues with drivers that do not handle interface down
                    * on a running supplicant properly.
                    */
                    mWifiNative.killSupplicant(mP2pSupported);
                    //开启wpa_supplicant
                    if(mWifiNative.startSupplicant(mP2pSupported)) {
                        setWifiState(WIFI_STATE_ENABLING);
                        if (DBG) log("Supplicant start successful");
                        mWifiMonitor.startMonitoring();
                        transitionTo(mSupplicantStartingState);
                    } else {
                        loge("Failed to start supplicant!");
                    }
                } else {
                    loge("Failed to load driver");
                }
                break;
//.......
}

1.WifiNative.loadDriver():加载Wifi驱动。
WifiNative.loadDriver()–>android_net_wifi_wifi.cpp(android_net_wifi_loadDriver)
->wifi.c(wifi_load_driver)。

2.mNwService.wifiFirmwareReload(mInterfaceName, “STA”); 加载固件

3.mWifiNative.startSupplicant(mP2pSupported) 先保证没有运行的wpa supplicant,然后开启wpa supplicant,其中参数mP2pSupported表示是否支持wifi 直连。
WifiNative.startSupplicant()–>android_net_wifi_wifi.cpp(android_net_wifi_startSupplicant)
->wifi.c(wifi_start_supplicant)。
4.setWifiState(WIFI_STATE_ENABLING) 发送广播(wifi状态改变 ,正在开启)。
5.mWifiMonitor.startMonitoring()
WifiMonitor创建一个线程MonitorThrad
1)connectToSupplicant最终调到wifi.c 中的wifi_connect_on_socket_path。在该函数中,将通过wpa_ctrl_open函数分别创 建两个socket,一个是ctrl_conn, 用于向wpa_supplicant发送命令并接收response, 另一个是monitor_conn, 它一直阻塞等待从wpa_supplicant过来的event。连接成功后WifiMonitor会向WifiStateMachine发送一个代表socket通信建立成功的消息:SUP_CONNECTION_EVENT。
2)mWifiNative.waitForEvent-》wifi_wait_on_socket ,循环调用该函数,接收底层事件并分发处理。
6.transitionTo(mSupplicantStartingState): WifiStateMachine切换到SupplicantStartingState状态。步骤5是在另一个线程中运行,并且是耗时操作,所以WifiStateMachine先切换到SupplicantStartingState状态,然后接收到SUP_CONNECTION_EVENT消息。

2.3 SupplicantStartingState
下面看看如何处理SUP_CONNECTION_EVENT消息。

class SupplicantStartingState extends State {
    @Override
    public boolean processMessage(Message message) {
        switch(message.what) {
            case WifiMonitor.SUP_CONNECTION_EVENT:
                if (DBG) log("Supplicant connection established");
                setWifiState(WIFI_STATE_ENABLED);
                mSupplicantRestartCount = 0;
                /* Reset the supplicant state to indicate the supplicant
                 * state is not known at this time */
                mSupplicantStateTracker.sendMessage(CMD_RESET_SUPPLICANT_STATE);
                /* Initialize data structures */
                mLastBssid = null;
                mLastNetworkId = WifiConfiguration.INVALID_NETWORK_ID;
                mLastSignalLevel = -1;

                mWifiInfo.setMacAddress(mWifiNative.getMacAddress());
                mWifiConfigStore.loadAndEnableAllNetworks();
                initializeWpsDetails();

                sendSupplicantConnectionChangedBroadcast(true);
                transitionTo(mDriverStartedState);
                break;
//......
}

1.setWifiState(WIFI_STATE_ENABLED),发送WIFI_STATE_ENABLED的广播。
2.WifiConfigStore.loadAndEnableAllNetworks() 加载并enable所有保存在wpa_supplicant中的AP。这样会使这些保存的wifi实现自动重连。
3.transitionTo(mDriverStartedState)切换到DriverStartedState状态。
DriverStartedState是SupplicantStartedState的子状态,所以先后运行SupplicantStartedState、DriverStartedState的enter方法。
2.4 SupplicantStartedState

class SupplicantStartedState extends State {
        @Override
        public void enter() {
            /* Wifi is available as long as we have a connection to supplicant */
            mNetworkInfo.setIsAvailable(true);

            int defaultInterval = mContext.getResources().getInteger(
                    R.integer.config_wifi_supplicant_scan_interval);
            mSupplicantScanIntervalMs = Settings.Global.getLong(mContext.getContentResolver(),
                    Settings.Global.WIFI_SUPPLICANT_SCAN_INTERVAL_MS,
                    defaultInterval);
            //设置扫描时间间隔。
            mWifiNative.setScanInterval((int)mSupplicantScanIntervalMs / 1000);
        }
//.....

1.mNetworkInfo.setIsAvailable(true); 连接到wpa_supplicant,就可以使用wifi。
2.frameworks/base/core/res/res/values/config.xml中可以修改config_wifi_supplicant_scan_interval 的值。
3.setScanInterval 设置wifi扫描间隔时间。

***2.5 DriverStartedState***
class DriverStartedState extends State {
        @Override
        public void enter() {
            mIsRunning = true;
            mInDelayedStop = false;
            mDelayedStopCounter++;
            updateBatteryWorkSource(null);
            /**
             * Enable bluetooth coexistence scan mode when bluetooth connection is active.
             * When this mode is on, some of the low-level scan parameters used by the
             * driver are changed to reduce interference with bluetooth
             */
            mWifiNative.setBluetoothCoexistenceScanMode(mBluetoothConnectionActive);
            /* set country code */
            setCountryCode();
            /* set frequency band of operation */
            setFrequencyBand();
            /* initialize network state */
            setNetworkDetailedState(DetailedState.DISCONNECTED);

            /* Remove any filtering on Multicast v6 at start */
            mWifiNative.stopFilteringMulticastV6Packets();

            /* Reset Multicast v4 filtering state */
            if (mFilteringMulticastV4Packets.get()) {
                mWifiNative.startFilteringMulticastV4Packets();
            } else {
                mWifiNative.stopFilteringMulticastV4Packets();
            }

            if (mOperationalMode != CONNECT_MODE) {
                mWifiNative.disconnect();
                transitionTo(mScanModeState);
            } else {
                /* Driver stop may have disabled networks, enable right after start */
                mWifiConfigStore.enableAllNetworks();
                mWifiNative.reconnect();
                // Status pulls in the current supplicant state and network connection state
                // events over the monitor connection. This helps framework sync up with
                // current supplicant state
                mWifiNative.status();
                transitionTo(mDisconnectedState);
            }

            // We may have missed screen update at boot
            if (mScreenBroadcastReceived.get() == false) {
                PowerManager powerManager = (PowerManager)mContext.getSystemService(
                        Context.POWER_SERVICE);
                handleScreenStateChanged(powerManager.isScreenOn());
            } else {
                // Set the right suspend mode settings
                mWifiNative.setSuspendOptimizations(mSuspendOptNeedsDisabled == 0
                        && mUserWantsSuspendOpt.get());
            }
            mWifiNative.setPowerSave(true);

            if (mP2pSupported) mWifiP2pChannel.sendMessage(WifiStateMachine.CMD_ENABLE_P2P);

            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);
        }
//.....

setBluetoothCoexistenceScanMode 启用蓝牙连接时启用蓝牙共存扫描模式。当此模式打开时,驱动程序使用的一些低级扫描参数会被更改,以减少对蓝牙的干扰。
mOperationalMode 默认为CONNECT_MODE,enableAllNetworks 将保存的wifi置为可连接的,并进行重连。
mWifiNative.status() 将wpa_supplicant中状态进行同步。
切换到DisconnectedState状态。

猜你喜欢

转载自blog.csdn.net/huangweiqing80/article/details/82702911