Android Q WiFi 启动流程分析

  • 1、WiFi 启动流程简介
  • 2、WiFi 启动流程应用层分析
  • 3、WiFi 启动流程服务层分析
  • 3.1 WifiController 分析
  • 3.2 WifiController 启动


1、WiFi 启动流程简介

用户可以通过systemUi和设置里的WiFi开关打开WiFi,这时候会调用到WiFi framework的相关接口,继而再继续往下启用具体的硬件完成WiFi启动流程

2、WiFi 启动流程应用层分析

在Android Setting 中,使用WifiEnabler 来控制WiFi 的开关操作,WifiEnabler 实现了OnSwitchChangeListener接口,当用户点击WiFi的开关按钮,就会回调到WifiEnabler onSwitchToggled 方法;在onSwitchToggled 方法调用WifiManager 的setWifiEnabled 方法来实现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, SettingsEnums.ACTION_WIFI_ON);
        } else {
            // Log if user was connected at the time of switching off.
            mMetricsFeatureProvider.action(mContext, SettingsEnums.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.1 、WifiManager 是WiFi 子系统的管理类,WiFi 子系统绝大部分功能都是通过WifiManager 来实现的,WifiManager 是Wifiserver 的代理类,通过AIDL 来调用Wifiserver 相应的函数。setWifiEnabled 函数实现如下:setWifiEnabled 调用mService setWifiEnabled 方法,mService 是IWifiManager 的实现,是Android wifiserver 的代理类,最终是调到WifiServiceImpl 的setWifiEnabled 方法

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

3、WiFi 启动流程服务层分析

WifiManager 的setWifiEnabled 最终调用到了WifiServiceImpl setWifiEnabled 方法,WifiServiceImpl setWifiEnabled 实现如下,参数STA_PRIMARY 表示打开的是主WiFi。如果第二个参数是STA_SECONDARY 则表示打开的是第二个WiFi。目前高通实现了WiFi 双STA 的功能,通过该参数来区别打开的哪一个WiFi。

@Override
public synchronized boolean setWifiEnabled(String packageName, boolean enable) {
    return setWifiEnabled2(packageName, STA_PRIMARY, enable);
}

WifiServiceImpl setWifiEnabled 调用setWifiEnabled2 方法,setWifiEnabled2 方法实现如下;首先判断应用是有权限打开WiFi ,在Android Q 中,需要有网络设置方面的权限才能打开WiFi ,setWifiEnabled 已经不是SDK 接口,不对第三方开放。只分析主WiFi的启动流程,辅助WiFi 暂时不分析,setWifiEnabled2 通过mWifiController 给自己发送CMD_WIFI_TOGGLED 消息。

public synchronized boolean setWifiEnabled2(String packageName, int staId, boolean enable) {
        if (enforceChangePermission(packageName) != MODE_ALLOWED) {
            return false;
        }

        boolean isPrivileged = isPrivileged(Binder.getCallingPid(), Binder.getCallingUid());
        if (!isPrivileged && !isDeviceOrProfileOwner(Binder.getCallingUid())
                && !mWifiPermissionsUtil.isTargetSdkLessThan(packageName, Build.VERSION_CODES.Q,
                  Binder.getCallingUid())
                && !isSystem(packageName, Binder.getCallingUid())) {
            mLog.info("setWifiEnabled not allowed for uid=%")
                    .c(Binder.getCallingUid()).flush();
            return false;
        }
        // If Airplane mode is enabled, only privileged apps are allowed to toggle Wifi
        if (mSettingsStore.isAirplaneModeOn() && !isPrivileged) {
            mLog.err("setWifiEnabled in Airplane mode: only Settings can toggle wifi").flush();
            return false;
        }

        // If SoftAp is enabled, only privileged apps are allowed to toggle wifi
        boolean apEnabled = mWifiApState == WifiManager.WIFI_AP_STATE_ENABLED;
        if (apEnabled && !isPrivileged) {
            mLog.err("setWifiEnabled SoftAp enabled: only Settings can toggle wifi").flush();
            return false;
        }

        // If we're in crypt debounce, ignore any wifi state change APIs.
        if (mFrameworkFacade.inStorageManagerCryptKeeperBounce()) {
            return false;
        }

        mLog.info("setWifiEnabled package=% uid=% enable=%").c(packageName)
                .c(Binder.getCallingUid()).c(enable).flush();
        long ident = Binder.clearCallingIdentity();
        try {
            if (staId == STA_PRIMARY && !mSettingsStore.handleWifiToggled(enable)) {
                // Nothing to do if wifi cannot be toggled
                return true;
            }
        } finally {
            Binder.restoreCallingIdentity(ident);
        }

        if (!mIsControllerStarted) {
            Slog.e(TAG,"WifiController is not yet started, abort setWifiEnabled");
            return false;
        }

        mWifiMetrics.incrementNumWifiToggles(isPrivileged, enable);

        if (staId == STA_PRIMARY) {
            mWifiController.sendMessage(CMD_WIFI_TOGGLED);
        } else if ((getNumConcurrentStaSupported() > 1)
                   && (getWifiEnabledState() == WifiManager.WIFI_STATE_ENABLED)
                   && staId > STA_PRIMARY) {
            mWifiController.sendMessage(CMD_ADD_WIFI_SET, staId, enable ? 1 : 0);
        } else {
           Slog.e(TAG,"setWifiEnabled not allowed for id:"+staId);
           return false;
        }

        return true;
    }

3.1 WifiController 分析

WifiController 是管理WiFi 开关状态的class,WifiController 是一个状态机,一共有六个状态,其中

DefaultState状态是另外五个状态的父状态。

android wifi 第二连接 androidwifi开启流程_启动流程

3.2 WifiController 启动

WifiController 是在WifiServiceImpl 中被启动的,在WifiServiceImpl checkAndStartWifi 方法的中调用了WifiController start 的方法

Log.d(TAG, "qcdbg= mWifiStateMachine.syncInitialize()");
if (!mClientModeImpl.syncInitialize(mClientModeImplChannel)) {
    Log.wtf(TAG, "Failed to initialize ClientModeImpl");
}
mWifiController.start();
mIsControllerStarted = true;

// If we are already disabled (could be due to airplane mode), avoid changing persist
// state here
if (wifiEnabled) {
    setWifiEnabled(mContext.getPackageName(), wifiEnabled);
}

WifiController start 方法实现如下,首先设置初始状态,如果是scanonly模式,设置初始状态为StaDisabledWithScanState,否则设置状态为StaDisabledState;注册一个广播接收器,监听WiFi SoftAP 和STA 状态改变的广播。

public void start() {
        boolean isAirplaneModeOn = mSettingsStore.isAirplaneModeOn();
        boolean isWifiEnabled = mSettingsStore.isWifiToggleEnabled();
        boolean isScanningAlwaysAvailable = mSettingsStore.isScanAlwaysAvailable();
        boolean isLocationModeActive = mWifiPermissionsUtil.isLocationModeEnabled();

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

        if (checkScanOnlyModeAvailable()) {
            setInitialState(mStaDisabledWithScanState);
        } else {
            setInitialState(mStaDisabledState);
        }
        IntentFilter filter = new IntentFilter();
        filter.addAction(WifiManager.WIFI_AP_STATE_CHANGED_ACTION);
        filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
        filter.addAction(LocationManager.MODE_CHANGED_ACTION);
        mContext.registerReceiver(
                new BroadcastReceiver() {
                    @Override
                    public void onReceive(Context context, Intent intent) {
                        String action = intent.getAction();
                        if (action.equals(WifiManager.WIFI_AP_STATE_CHANGED_ACTION)) {
                            int state = intent.getIntExtra(
                                    WifiManager.EXTRA_WIFI_AP_STATE,
                                    WifiManager.WIFI_AP_STATE_FAILED);
                            if (state == WifiManager.WIFI_AP_STATE_FAILED) {
                                Log.e(TAG, "SoftAP start failed");
                                sendMessage(CMD_AP_START_FAILURE);
                            } else if (state == WifiManager.WIFI_AP_STATE_DISABLED) {
                                sendMessage(CMD_AP_STOPPED);
                            }
                        } else if (action.equals(LocationManager.MODE_CHANGED_ACTION) && mWifiControllerReady) {
                            // Location mode has been toggled...  trigger with the scan change
                            // update to make sure we are in the correct mode
                            sendMessage(CMD_SCAN_ALWAYS_MODE_CHANGED);
                        }
                    }
                },
                new IntentFilter(filter));
        super.start();
    }

我们打开WiFi的时候,并非sanonly 模式,所以WifiController 初始化状态为StaDisabledState ;在StaDisabledState 状态机中处理了CMD_WIFI_TOGGLED 消息,CMD_WIFI_TOGGLED 主要是切换WifiController 的状态,让WifiController 进入StaEnabledState 状态

public boolean processMessage(Message msg) {
            switch (msg.what) {
                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(mStaEnabledState);
                    } else if (checkScanOnlyModeAvailable()) {
                        // only go to scan mode if we aren't in airplane mode
                        if (mSettingsStore.isAirplaneModeOn()) {
                            transitionTo(mStaDisabledWithScanState);
                        }
                    }
                    break;

进入StaEnabledState 状态首先调用的是StaEnabledState 状态机的 enter 方法,enter 调用mActiveModeWarden 对象enterClientMode 方法

public void enter() {
    log("StaEnabledState.enter()");
    mActiveModeWarden.enterClientMode();
}

enterClientMode 实现如下

public void enterClientMode() {
        changeMode(ModeStateMachine.CMD_START_CLIENT_MODE);
    }

changeMode 实现,

private void changeMode(int newMode) {
    mModeStateMachine.sendMessage(newMode);
}

ModeStateMachine 也是一个状态机,有三个状态 ClientModeActiveState、ScanOnlyModeActiveState、WifiDisabledState;这三个状态相互独立,没有父子关系,初始状态被设置为 WifiDisabledState

ModeStateMachine() {
    super(TAG, mLooper);

    addState(mClientModeActiveState);
    addState(mScanOnlyModeActiveState);
    addState(mWifiDisabledState);

    Log.d(TAG, "Starting Wifi in WifiDisabledState");
    setInitialState(mWifiDisabledState);
    start();
}

WifiDisabledState 状态机对消息处理方法如下

public boolean processMessage(Message message) {
    Log.d(TAG, "received a message in WifiDisabledState: " + message);
    if (checkForAndHandleModeChange(message)) {
        return HANDLED;
    }
    return NOT_HANDLED;
}

最终是调用checkForAndHandleModeChange 对消息进行处理,从上面可知,我们发给WifiDisabledState 状态的消息为CMD_START_CLIENT_MODE ,对CMD_START_CLIENT_MODE 的处理是 ModeStateMachine 状态机切换到 ClientModeActiveState 状态

private boolean checkForAndHandleModeChange(Message message) {
    switch(message.what) {
        case ModeStateMachine.CMD_START_CLIENT_MODE:
            Log.d(TAG, "Switching from " + getCurrentMode() + " to ClientMode");
            if (getCurrentMode().equals(mClientModeActiveState.getName()))
                return NOT_HANDLED;
            mModeStateMachine.transitionTo(mClientModeActiveState);
            break;
        case ModeStateMachine.CMD_START_SCAN_ONLY_MODE:
            Log.d(TAG, "Switching from " + getCurrentMode() + " to ScanOnlyMode");
            if (getCurrentMode().equals(mScanOnlyModeActiveState.getName()))
                return NOT_HANDLED;
            mModeStateMachine.transitionTo(mScanOnlyModeActiveState);
            break;
        case ModeStateMachine.CMD_DISABLE_WIFI:
            Log.d(TAG, "Switching from " + getCurrentMode() + " to WifiDisabled");
            if (getCurrentMode().equals(mWifiDisabledState.getName()))
                return NOT_HANDLED;
            mModeStateMachine.transitionTo(mWifiDisabledState);
            break;
        default:
            return NOT_HANDLED;
    }
    return HANDLED;
}

ModeStateMachine 状态机切换到ClientModeActiveState 状态,首先执行ClientModeActiveState 状态的enter 方法,首先构造一个Manager 是ActiveModeManager 的对象,ActiveModeManager 是一个接口,对于STA模式它的实现类是ClientModeManager

@Override
        public void enter() {
            Log.d(TAG, "Entering ClientModeActiveState");

            mListener = new ClientListener();
            mManager = mWifiInjector.makeClientModeManager(mListener);
            mManager.start();
            mActiveModeManagers.add(mManager);

            updateBatteryStatsWifiState(true);
        }

makeClientModeManager 方法实现如下:

public ClientModeManager makeClientModeManager(ClientModeManager.Listener listener) {
    return new ClientModeManager(mContext, mWifiCoreHandlerThread.getLooper(),
            mWifiNative, listener, mWifiMetrics, mClientModeImpl);
}

mManager.start 方法调用的就是ClientModeManager 中的start 方法;ClientModeManager 构造方法如下

ClientModeManager(Context context, @NonNull Looper looper, WifiNative wifiNative,
        Listener listener, WifiMetrics wifiMetrics, ClientModeImpl clientModeImpl) {
    mContext = context;
    mWifiNative = wifiNative;
    mListener = listener;
    mWifiMetrics = wifiMetrics;
    mClientModeImpl = clientModeImpl;
    mStateMachine = new ClientModeStateMachine(looper);
}

ClientModeManager 的start 方法如下

public void start() {
    mStateMachine.sendMessage(ClientModeStateMachine.CMD_START);
}

从ClientModeManager 的构造方法中可知mStateMachine 对象为类ClientModeStateMachine ,ClientModeStateMachine 也是一个状态机,一个有两个独立的状态 mIdleState、mStartedState,初始状态为mIdleState 。

ClientModeStateMachine(Looper looper) {
    super(TAG, looper);

    addState(mIdleState);
    addState(mStartedState);

    setInitialState(mIdleState);
    start();
}

当ClientModeManager 收到消息CMD_START 处理如下,调用WifiNative setupInterfaceForClientInConnectivityMode 方法来设置底层接口

public boolean processMessage(Message message) {
    switch (message.what) {
        case CMD_START:
            updateWifiState(WifiManager.WIFI_STATE_ENABLING,
                            WifiManager.WIFI_STATE_DISABLED);

            mClientInterfaceName =
                    mWifiNative.setupInterfaceForClientInConnectivityMode(
                    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;
            }
            transitionTo(mStartedState);
            break;

setupInterfaceForClientInConnectivityMode 方法实现如下,setupInterfaceForClientInConnectivityMode 做的事情很多,主要是启动vendor HAL ,启动wpa_supplicant ,设置接口的client mode ,启动监听对应wlan 的事件。在这里只是笼统总结下,该函数后续单独分析

public String setupInterfaceForClientInConnectivityMode(
        @NonNull InterfaceCallback interfaceCallback, boolean lowPriority) {
    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_FOR_CONNECTIVITY);
        if (iface == null) {
            Log.e(TAG, "Failed to allocate new STA iface");
            return null;
        }
        iface.externalListener = interfaceCallback;
        iface.name = createStaIface(iface, lowPriority);
        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 (!setupFstInterface(iface)) {
            Log.e(TAG, "Failed to setup fst interface from: " + iface);
            teardownInterface(iface.name);
            mWifiMetrics.incrementNumSetupClientInterfaceFailureDueToWificond();
            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);

        iface.featureSet = getSupportedFeatureSetInternal(iface.name);
        return iface.name;
    }
}

setupInterfaceForClientInConnectivityMode 方法执行完后,ClientModeManager 状态机切换到mStartedState 状态,首先执行mStartedState 的enter方法,在enter 中调用了onUpChanged 的方法

@Override
public void enter() {
    Log.d(TAG, "entering StartedState");
    mIfaceIsUp = false;
    onUpChanged(mWifiNative.isInterfaceUp(mClientInterfaceName));
}

onUpChanged 实现如下,在setupInterfaceForClientInConnectivityMode 方法中,已经把对应的wlan 口设置好,并up起来 ,所有调用这里的时候isUP 是true,调用ClientModeImpl setOperationalMode 设置ClientModeImpl 的状态。ClientModeImpl 的STA 模式的主要的控制状态机,控制的WiFi 的连接,获取ip等流程。后面单独分析该状态机

private void onUpChanged(boolean isUp) {
                if (isUp == mIfaceIsUp) {
                    return;  // no change
                }
                mIfaceIsUp = isUp;
                if (isUp) {
                    Log.d(TAG, "Wifi is ready to use for client mode");
                    mClientModeImpl.setOperationalMode(ClientModeImpl.CONNECT_MODE,
                                                       mClientInterfaceName);
                    updateWifiState(WifiManager.WIFI_STATE_ENABLED,
                                    WifiManager.WIFI_STATE_ENABLING);
                } else {
                    if (mClientModeImpl.isConnectedMacRandomizationEnabled()) {
                        // Handle the error case where our underlying interface went down if we
                        // do not have mac randomization enabled (b/72459123).
                        return;
                    }
                    // if the interface goes down we should exit and go back to idle state.
                    Log.d(TAG, "interface down!");
                    updateWifiState(WifiManager.WIFI_STATE_UNKNOWN,
                                    WifiManager.WIFI_STATE_ENABLED);
                    mStateMachine.sendMessage(CMD_INTERFACE_DOWN);
                }
            }

setOperationalMode 实现如下,由于第一个参数为CONNECT_MODE,所以设置ClientModeImpl 状态机进入mDisconnectedState模式,进入mDisconnectedState会触发一次连接扫描,该流程以后分析,到此,WiFi 的启动流程基本走完。

public void setOperationalMode(int mode, String ifaceName) {
        if (mVerboseLoggingEnabled) {
            log("setting operational mode to " + String.valueOf(mode) + " for iface: " + ifaceName);
        }

        new Exception().printStackTrace();

        mModeChange = true;
        if (mode != CONNECT_MODE) {
            // we are disabling client mode...   need to exit connect mode now
            transitionTo(mDefaultState);
        } else {
            // do a quick sanity check on the iface name, make sure it isn't null
            if (ifaceName != null) {
                mInterfaceName = ifaceName;
                transitionTo(mDisconnectedState);
            } else {
                Log.e(TAG, "supposed to enter connect mode, but iface is null -> DefaultState");
                transitionTo(mDefaultState);
            }
        }
        // use the CMD_SET_OPERATIONAL_MODE to force the transitions before other messages are
        // handled.
        sendMessageAtFrontOfQueue(CMD_SET_OPERATIONAL_MODE);
    }