美文网首页蓝牙和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