美文网首页蓝牙和WIFI
Wifi笔记 | 启动流程 Manager层

Wifi笔记 | 启动流程 Manager层

作者: 力卉编程 | 来源:发表于2020-01-02 10:07 被阅读0次

    一、先上流程

    wifi1.png

    二、代码流程

    2.1 应用层
    2.1.1 入口
    //packages/apps/settings/WifiSettings.java
    @Override
    public void onStart() {
        super.onStart();
     
        // On/off switch is hidden for Setup Wizard (returns null)
        mWifiEnabler = createWifiEnabler();
     
        if (mIsRestricted) {
            restrictUi();
            return;
        }
     
        onWifiStateChanged(mWifiManager.getWifiState());
    }
    private WifiEnabler createWifiEnabler() {
        final SettingsActivity activity = (SettingsActivity) getActivity();
         return new WifiEnabler(activity, new SwitchBarController(activity.getSwitchBar()),
                mMetricsFeatureProvider);
    }
    
    2.1.2 监听动作:开启Wifi开关变会有下面的操作。
    
    @Override
        public boolean onSwitchToggled(boolean isChecked) {
        //Do nothing if called as a result of a state machine event
        if (mStateMachineEvent) {
            return true;
        }
        // Show toast message if Wi-Fi is not allowed in airplane mode
        if (isChecked && !WirelessUtils.isRadioAllowed(mContext, Settings.Global.RADIO_WIFI)) {
            Toast.makeText(mContext, R.string.wifi_in_airplane_mode, Toast.LENGTH_SHORT).show();
            // Reset switch to off. No infinite check/listener loop.
            mSwitchWidget.setChecked(false);
            return false;
        }
     
        if (isChecked) {
            mMetricsFeatureProvider.action(mContext, MetricsEvent.ACTION_WIFI_ON);
        } else {
            // Log if user was connected at the time of switching off.
            mMetricsFeatureProvider.action(mContext, MetricsEvent.ACTION_WIFI_OFF,
            mConnected.get());
        }
        if (!mWifiManager.setWifiEnabled(isChecked)) {
            // Error
            mSwitchWidget.setEnabled(true);
            Toast.makeText(mContext, R.string.wifi_error, Toast.LENGTH_SHORT).show();
        }
        return true;
    }
    
    2.2 java 框架层
    2.2.1 入口 WifiManager.java
    //frameworks/base/wifi/java/android/net/wifi/WifiManager.java
    public boolean setWifiEnabled(boolean enabled) {
        try {
            return mService.setWifiEnabled(mContext.getOpPackageName(), enabled);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }
    //调用service的接口aidl
    //frameworks/base/wifi/java/android/net/wifi/IWifiManager.aidl
    boolean setWifiEnabled(String packageName, boolean enable);
    
    2.2.2 实现 WifiSeviceImpl.java
    //frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiSeviceImpl.java
    @Override
    public synchronized boolean setWifiEnabled(String packageName, boolean enable)throws RemoteException {
        if (enforceChangePermission(packageName) != MODE_ALLOWED) {            return false;
        }
     
        Slog.d(TAG, "setWifiEnabled: " + enable + " pid=" + Binder.getCallingPid()
                + ", uid=" + Binder.getCallingUid() + ", package=" + packageName);
        mLog.info("setWifiEnabled package=% uid=% enable=%").c(packageName).c(Binder.getCallingUid()).c(enable).flush();
     
        boolean isFromSettings = checkNetworkSettingsPermission(
                    Binder.getCallingPid(), Binder.getCallingUid());
     
        // If Airplane mode is enabled, only Settings is allowed to toggle Wifi
        if (mSettingsStore.isAirplaneModeOn() && !isFromSettings) {
                mLog.info("setWifiEnabled in Airplane mode: only Settings can enable wifi").flush();
                return false;
        }
     
        // If SoftAp is enabled, only Settings is allowed to toggle wifi
        boolean apEnabled = mWifiApState == WifiManager.WIFI_AP_STATE_ENABLED;
     
        if (apEnabled && !isFromSettings) {
            mLog.info("setWifiEnabled SoftAp not disabled: only Settings can enable wifi").flush();
            return false;
        }
     
        /*
        * 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);
            }
     
     
        if (mPermissionReviewRequired) {
            final int wiFiEnabledState = getWifiEnabledState();
            if (enable) {
                if (wiFiEnabledState == WifiManager.WIFI_STATE_DISABLING
                        || wiFiEnabledState == WifiManager.WIFI_STATE_DISABL){
                    if (startConsentUi(packageName, Binder.getCallingUid(),
                        WifiManager.ACTION_REQUEST_ENABLE)) {
                            return true;
                    }
            }
            } else if (wiFiEnabledState == WifiManager.WIFI_STATE_ENABLING
                || wiFiEnabledState == WifiManager.WIFI_STATE_ENABLED) {
                    if (startConsentUi(packageName, Binder.getCallingUid(),
                        WifiManager.ACTION_REQUEST_DISABLE)) {
                            return true;
                    }
            }
        }
        mWifiController.sendMessage(CMD_WIFI_TOGGLED);
        return true;
    }
    

    解释:
    WifiManager.setWifiEnabled通过aidl跨进程调用到了WifiServiceImpl.setWifiEnabled,
    其中WifiServiceImpl是WifiService的实现类。
    在WifiServiceImpl的setWifiEnabled方法里做的一些事情:

    • enforceChangePermission 判断调用的进程是否有权限。想要开关wifi需要CHANGE_WIFI_STATE 权限。
    • isAirplaneModeOn 判断飞行模式。
    • handleWifiToggled 保存wifi 操作的状态。
    • 向【WifiController】发送CMD_WIFI_TOGGLED消息。
    2.2.3 WifiController处理

    WifiController,是一个状态机,可能Android每个版本的状态机不完全一样,比如Android P 和Android O比起来状态机减少了一些分支。 WifiController在WIfiServiceImpl的构造函数中初始化、并开始运行。
    WifiController 和WifiStateMachine 不同,WifiStateMachine是一个复杂的状态机,它维护了Wifi的启动、扫描、连接、断开等多个状态。WifiController 是高级别的wifi状态机,因为它管理的状态是wifi开关,wifi热点开关等状态,只有在wifi开关等具体状态下,判断wifi处于启动扫描附近热点状态等才是有意义的。

    //frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiController.java
    WifiController(Context context, WifiStateMachine wsm, Looper                        
            wifiStateMachineLooper, WifiSettingsStore wss, Looper                                   
            wifiServiceLooper, FrameworkFacade f,WifiStateMachinePrime wsmp) {
        super(TAG, wifiServiceLooper);
        ...
     
        // CHECKSTYLE:OFF IndentationCheck
        addState(mDefaultState);
            addState(mStaDisabledState, mDefaultState);
            addState(mStaEnabledState, mDefaultState);
                addState(mDeviceActiveState, mStaEnabledState);
            addState(mStaDisabledWithScanState, mDefaultState);
            addState(mEcmState, mDefaultState);
        // CHECKSTYLE:ON IndentationCheck
        ...
     
        if (checkScanOnlyModeAvailable()) {
            setInitialState(mStaDisabledWithScanState);
        }else {
            setInitialState(mStaDisabledState);
        }
        //...
    }
    
    WifiController状态机各状态关系:
    状态机关系图

    状态机初始状态为StaDisabledState,在该状态下对CMD_WIFI_TOGGLED消息的处理:

    在DeviceActiveState状态下主要做了两个操作:

    • mWifiStateMachinePrime.enterClientMode()
    • mWifiStateMachine.setHighPerfModeEnabled(false)

    接下来,我们主要看mWifiStateMachinePrime.enterClientMode()。

    2.2.4 ClientMode模式
    //frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiStateMachinePrime.java
    /**
    * Method to switch wifi into client mode where connections to configured networks will be
    * attempted.
    */
    public void enterClientMode() {
        changeMode(ModeStateMachine.CMD_START_CLIENT_MODE);
    }
    private void changeMode(int newMode) {
        mModeStateMachine.sendMessage(newMode);
    }
    

    ModeStateMachine又是一个状态机,不过这个状态机比较简单只有三个状态,初始状态为WifiDisabledState。

    2.2.5 ModeStateMachine状态机处理
    private class ModeStateMachine extends StateMachine {
        // Commands for the state machine  - these will be removed,
        // along with the StateMachine itself
        public static final int CMD_START_CLIENT_MODE    = 0;
        public static final int CMD_START_SCAN_ONLY_MODE = 1;
        public static final int CMD_DISABLE_WIFI         = 3;
     
        private final State mWifiDisabledState = new WifiDisabledState();
        private final State mClientModeActiveState = new ClientModeActiveState();
        private final State mScanOnlyModeActiveState = new ScanOnlyModeActiveState();
     
        ModeStateMachine() {
            super(TAG, mLooper);
     
            addState(mClientModeActiveState);
            addState(mScanOnlyModeActiveState);
            addState(mWifiDisabledState);
     
            Log.d(TAG, "Starting Wifi in WifiDisabledState");
            setInitialState(mWifiDisabledState);
            start();
            ...
        }
    }
    

    状态机从WifiDisabledState状态转向ClientModeActiveState状态,所以再继续看ClientModeActiveState。
    ClientModeActiveState将进入ActiveModeManager

    2.2.6 ActiveModeManager
    //frameworks/opt/net/wifi/service/java/com/android/server/wifi/ClientModeManager.java
    /**
    * Start client mode.
    */
    public void start() {
        mStateMachine.sendMessage(ClientModeStateMachine.CMD_START);
    }
    private class ClientModeStateMachine extends StateMachine {
        // Commands for the state machine.
        public static final int CMD_START = 0;
        public static final int CMD_INTERFACE_STATUS_CHANGED = 3;
        public static final int CMD_INTERFACE_DESTROYED = 4;
        public static final int CMD_INTERFACE_DOWN = 5;
        private final State mIdleState = new IdleState();
        private final State mStartedState = new StartedState();
        ...
     
        ClientModeStateMachine(Looper looper) {
            super(TAG, looper);
     
            addState(mIdleState);
            addState(mStartedState);
     
            setInitialState(mIdleState);
            start();
        }
        ...
    }
    
    2.2.7 Idlesate状态

    此状态机将让wifi进入到Native层,
    请关注:mWifiNative.setupInterfaceForClientMode的操作。

    private class IdleState extends State {
     
        @Override
        public void enter() {
            Log.d(TAG, "entering IdleState");
            mClientInterfaceName = null;
            mIfaceIsUp = false;
        }
     
        @Override
        public boolean processMessage(Message message) {
            switch (message.what) {
                case CMD_START:
                    updateWifiState(WifiManager.WIFI_STATE_ENABLING,
                            WifiManager.WIFI_STATE_DISABLED);
     
                    mClientInterfaceName = mWifiNative.setupInterfaceForClientMode(
                            false /* not low priority */, mWifiNativeInterfaceCallback);
                    if (TextUtils.isEmpty(mClientInterfaceName)) {
                        Log.e(TAG, "Failed to create ClientInterface. Sit in Idle");
                        updateWifiState(WifiManager.WIFI_STATE_UNKNOWN,
                                WifiManager.WIFI_STATE_ENABLING);
                        updateWifiState(WifiManager.WIFI_STATE_DISABLED,
                                WifiManager.WIFI_STATE_UNKNOWN);
                        break;
                    }
                    sendScanAvailableBroadcast(false);
                    mScanRequestProxy.enableScanningForHiddenNetworks(false);
                    mScanRequestProxy.clearScanResults();
                    transitionTo(mStartedState);
                    break;
                default:
                    Log.d(TAG, "received an invalid message: " + message);
                    return NOT_HANDLED;
            }
            return HANDLED;
        }
    }
    

    3 Native层

    3.1 入口及调用
    • 启动Hal:startHal()
    • 启动supplicant:startSupplicant()
    • 加载驱动(loadDriver):setupInterfaceForClientMode()
    • 启动WifiMonitor:WifiMonitor.startMonitoring()
    //frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiNative.java
    /**
    * Setup an interface for Client mode operations.
    *
    * * This method configures an interface in STA mode in all the native daemons
    * (wificond, wpa_supplicant & vendor HAL).
    *
    * @param lowPrioritySta The requested STA has a low request priority (lower probability of
    *                       getting created, higher probability of getting destroyed).
    * @param interfaceCallback Associated callback for notifying status changes for the iface.
    * @return Returns the name of the allocated interface, will be null on failure.
    */
    public String setupInterfaceForClientMode(boolean lowPrioritySta,
    @NonNull InterfaceCallback interfaceCallback) {
        synchronized (mLock) {
            if (!startHal()) {
                Log.e(TAG, "Failed to start Hal");
                mWifiMetrics.incrementNumSetupClientInterfaceFailureDueToHal();
                return null;
            }
            if (!startSupplicant()) {
                Log.e(TAG, "Failed to start supplicant");
                mWifiMetrics.incrementNumSetupClientInterfaceFailureDueToSupplicant();
                return null;
            }
            Iface iface = mIfaceMgr.allocateIface(Iface.IFACE_TYPE_STA);
            if (iface == null) {
                Log.e(TAG, "Failed to allocate new STA iface");
                return null;
            }
            iface.externalListener = interfaceCallback;
            iface.name = createStaIface(iface, lowPrioritySta);
            if (TextUtils.isEmpty(iface.name)) {
                Log.e(TAG, "Failed to create STA iface in vendor HAL");
                mIfaceMgr.removeIface(iface.id);
                mWifiMetrics.incrementNumSetupClientInterfaceFailureDueToHal();
                return null;
            }
            if (mWificondControl.setupInterfaceForClientMode(iface.name) == null) {
                Log.e(TAG, "Failed to setup iface in wificond on " + iface);
                teardownInterface(iface.name);
                mWifiMetrics.incrementNumSetupClientInterfaceFailureDueToWificond();
                return null;
            }
            if (!mSupplicantStaIfaceHal.setupIface(iface.name)) {
                Log.e(TAG, "Failed to setup iface in supplicant on " + iface);
                teardownInterface(iface.name);
                mWifiMetrics.incrementNumSetupClientInterfaceFailureDueToSupplicant();
                return null;
            }
            iface.networkObserver = new NetworkObserverInternal(iface.id);
            if (!registerNetworkObserver(iface.networkObserver)) {
                Log.e(TAG, "Failed to register network observer on " + iface);
                teardownInterface(iface.name);
                return null;
            }
            mWifiMonitor.startMonitoring(iface.name);
            // Just to avoid any race conditions with interface state change callbacks,
            // update the interface state before we exit.
            onInterfaceStateChanged(iface, isInterfaceUp(iface.name));
            initializeNwParamsForClientInterface(iface.name);
            Log.i(TAG, "Successfully setup " + iface);
            return iface.name;
        }
    }
    

    总结:
    WifiMonitor.startMonitoring():这一步主要是在WifiMonitor中建立与wpa_supplicant通信的socket通道、创建一个线程接收底层事件并分发处理。这里会创建两个socket通道与wpa_s通信,一个用于下发指令,另一个用于接收事件。成功后WifiMonitor会向WifiStateMachine发送一个代表socket通信建立成功的消息:SUP_CONNECTION_EVENT;收到这个消息就表示Wifi已经启动成功了。

    Android P和Android O相比还是有不少变化的,主要是关键性的操作不再走WifiStateMachine这个线了,而是通过另外两个比较简单的状态机ModeStateMachine和ClientModeStateMachine。

    接下来将详解Wifi的Native的流程。

    完~~

    文 | 力卉编程

    相关文章

      网友评论

        本文标题:Wifi笔记 | 启动流程 Manager层

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