AndroidP wifi启动流程

从AndroidO到AndroidP,Wifi架构上还是发生了挺多变化的。接口上也在发生变化,所以网上的很多的流程梳理已经跟当前的代码逻辑有一些差异了。不过还好,总体上,只要懂了一个版本的代码,看其他版本问题已经不是很大。

梳理还是简单易懂为要务。
调用WifiManager中的setWifiEabled()开启wifi:

    public boolean setWifiEnabled(boolean enabled) {
        try {
            return mService.setWifiEnabled(getContext().getOpPackageName(), enabled);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

通过aidl调用到系统进程中的服务类WifiServiceImpl.java中:

    public synchronized boolean setWifiEnabled(String packageName, boolean enable)
            throws RemoteException {
        enforceChangePermission();
        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 =
                mWifiStateMachine.syncGetWifiApState() != WifiManager.WIFI_AP_STATE_DISABLED;
        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_DISABLED) {
                    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;
    }

此段代码逻辑中有涉及到权限检测,以及wifi开关状态保存等操作,最终调用到了如下方法:
mWifiController.sendMessage(CMD_WIFI_TOGGLED);
WifiController是一个状态机,接收到消息会根据处理逻辑进行不同状态的跳转,如下代码

        if (checkScanOnlyModeAvailable()) {
            setInitialState(mStaDisabledWithScanState);
        } else {
            setInitialState(mStaDisabledState);
        }

WifiController的初始状态为mStaDisabledState,所以CMD_WIFI_TOGGLED消息应该在此状态下处理,查看其处理逻辑:

                case CMD_WIFI_TOGGLED:
                    if (mSettingsStore.isWifiToggleEnabled()) {
                        if (doDeferEnable(msg)) {
                            if (mHaveDeferredEnable) {
                                //  have 2 toggles now, inc serial number and ignore both
                                mDeferredEnableSerialNumber++;
                            }
                            mHaveDeferredEnable = !mHaveDeferredEnable;
                            break;
                        }
                        transitionTo(mDeviceActiveState);
                    } else if (checkScanOnlyModeAvailable()) {
                        // only go to scan mode if we aren't in airplane mode
                        if (mSettingsStore.isAirplaneModeOn()) {
                            transitionTo(mStaDisabledWithScanState);
                        }
                    }
                    break;

代码逻辑大致为:

  • 先判断当前设备状态是否支持打开wifi,如下方法:
    public synchronized boolean isWifiToggleEnabled() {
        if (!mCheckSavedStateAtBoot) {
            mCheckSavedStateAtBoot = true;
            if (testAndClearWifiSavedState()) return true;
        }

        if (mAirplaneModeOn) {
            return mPersistWifiState == WIFI_ENABLED_AIRPLANE_OVERRIDE;
        } else {
            return mPersistWifiState != WIFI_DISABLED;
        }
    }

有涉及到飞行模式的相关考虑。

  • 检测是否两次点击调用开启wifi是否时间差太短,如果太短,消息延时处理,否则的话直接跳转到mDeviceActiveState
  • 如果wifi当前不支持打开,而此时“wifi scan always开关”打开,我们仍然要打开wifi,进入到mStaDisabledWithScanState状态。

接着上面的第二个步骤,当我们跳转到mDeviceActiveState之后,会继续相关逻辑处理。
WifiController状态机此时会用到,如下:

        addState(mDefaultState);
            addState(mStaDisabledState, mDefaultState);
            addState(mStaEnabledState, mDefaultState);
                addState(mDeviceActiveState, mStaEnabledState);
            addState(mStaDisabledWithScanState, mDefaultState);
            addState(mEcmState, mDefaultState);

进入到mDeviceActiveState之后会调用其enter方法,调用如下两个方法:

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

通过查阅代码逻辑,可以看出:

    /**
     * Method to switch wifi into client mode where connections to configured networks will be
     * attempted.
     */
    public void enterClientMode() {
        int mode = ModeStateMachine.CMD_START_CLIENT_MODE;
        if (mIsSupportCucc) {
            final FrameworkFacade facade = mWifiInjector.getFrameworkFacade();
            int networktype = facade.getIntegerSetting(mContext,
                    Global.NETWORK_PREFERENCE, WIFI_DATA_TYPE);
            int mobileDataStatus = facade.getIntegerSetting(mContext,
                    Global.MOBILE_DATA, MOBILE_DATA_ENABLE);

            if (mobileDataStatus == MOBILE_DATA_ENABLE && networktype == MOBILE_DATA_TYPE) {
                Log.d(TAG, "CUCC, client mode isn't allowed now, enter scan only mode");
                mode = ModeStateMachine.CMD_START_SCAN_ONLY_MODE;
            }
        }
        changeMode(mode);
    }

看注释大意为:
使wifi跳转到client模式的一种方法,客户端模式中,

你可能感兴趣的:(AndroidP wifi启动流程)