Wifi模块—源码分析Wifi启动1(Android P)

一 前言

      android框架层的函数调用是出了名的绕,开发者可能因为各种原因比如避免冲突、条件判断、函数封装等等各种各样需要考虑的因素而使得框架层的方法调用显得比较长,所以看源码的时候先看大体流程,有需要再深入某些重要的细节。不然一入源码深似海,会淹没在茫茫源码中。繁杂的东西,自己只要不凌乱,找好线索,进行总结,便会简单。

二 图示调用流程

                                          

三 代码具体流程

1 应用层

1.1 packages/apps/settings/WifiSettings.java

 在onStart()创建一个WifiEnabler对象,实现wifi开关功能。

@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);
}

1.2 packages/apps/settings/WifiEnabler.java

开启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;
}

 点击开关会调用mWifiManager.setWifiEnabled。

2 java 框架层

2.1 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();
    }
}

2.2 frameworks/base/wifi/java/android/net/wifi/IWifiManager.aidl

boolean setWifiEnabled(String packageName, boolean enable);

2.3 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.4 frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiController.java

        首先讲一下WifiController,它是一个状态机,可能Android每个版本的状态机不完全一样,比如Android P 和Android O比起来状态机减少了一些分支。 WifiController在WIfiServiceImpl的构造函数中初始化、并开始运行。

         WifiController 和WifiStateMachine 不同,WifiStateMachine是一个复杂的状态机,它维护了Wifi的启动、扫描、连接、断开等多个状态。WifiController 是高级别的wifi状态机,因为它管理的状态是wifi开关,wifi热点开关等状态,只有在wifi开关等具体状态下,判断wifi处于启动扫描附近热点状态等才是有意义的。

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消息的处理:

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

    @Override
    public void enter() {
        mWifiStateMachinePrime.disableWifi();
        // Supplicant can't restart right away, so note 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:
                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;
            ...
                
            default:
                return NOT_HANDLED;
        }
        return HANDLED;
    }
}

   在StaDisabledState状态下没做什么处理,接着转换到DeviceActiveState状态,StaEnabledState是它的父状态,由StateMachine的知识可知,转换到该状态时,会依次调用父、子状态的enter()函数。先看DeviceActiveState的父状态StaEnabledState:

class StaEnabledState extends State {
    @Override
        public void enter() {
            log("StaEnabledState.enter()");
        }

        @Override
        public boolean processMessage(Message msg) {
            switch (msg.what) {
                case CMD_WIFI_TOGGLED:
                    if (! mSettingsStore.isWifiToggleEnabled()) {
                        if (checkScanOnlyModeAvailable()) {
                            transitionTo(mStaDisabledWithScanState);
                        } else {
                            transitionTo(mStaDisabledState);
                        }
                    }
                    break;
                ...
                
}

StaEnabledState状态下也没做什么处理,再接着看DeviceActiveState状态:

/**
* Parent: StaEnabledState
*
* TODO (b/79209870): merge DeviceActiveState and StaEnabledState into a single state
*/
class DeviceActiveState extends State {
    @Override
    public void enter() {
        mWifiStateMachinePrime.enterClientMode();
        mWifiStateMachine.setHighPerfModeEnabled(false);
    }
    ...
}
            

可以看到在DeviceActiveState状态下主要做了两个操作mWifiStateMachinePrime.enterClientMode()和
        mWifiStateMachine.setHighPerfModeEnabled(false),主要看mWifiStateMachinePrime.enterClientMode()。

2.5 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。

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

那就看看ModeStateMachine的相关处理,先是在初始状态WifiDisabledState中。

class WifiDisabledState extends ModeActiveState {
    @Override
    public void enter() {
        Log.d(TAG, "Entering WifiDisabledState");
        mDefaultModeManager.sendScanAvailableBroadcast(mContext, false);
        mScanRequestProxy.enableScanningForHiddenNetworks(false);
        mScanRequestProxy.clearScanResults();
    }

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

    @Override
    public void exit() {
        // do not have an active mode manager...  nothing to clean up
    }
}
private boolean checkForAndHandleModeChange(Message message) {
    switch(message.what) {
        case ModeStateMachine.CMD_START_CLIENT_MODE:
            Log.d(TAG, "Switching from " + getCurrentMode() + " to ClientMode");
            mModeStateMachine.transitionTo(mClientModeActiveState);
            break;
        case ModeStateMachine.CMD_START_SCAN_ONLY_MODE:
            Log.d(TAG, "Switching from " + getCurrentMode() + " to ScanOnlyMode");
            mModeStateMachine.transitionTo(mScanOnlyModeActiveState);
            break;
        case ModeStateMachine.CMD_DISABLE_WIFI:
            Log.d(TAG, "Switching from " + getCurrentMode() + " to WifiDisabled");
            mModeStateMachine.transitionTo(mWifiDisabledState);
            break;
        default:
            return NOT_HANDLED;
    }
    return HANDLED;
}

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

class ClientModeActiveState extends ModeActiveState {
    ClientListener mListener;
    private class ClientListener implements ClientModeManager.Listener {
        @Override
        public void onStateChanged(int state) {
            // make sure this listener is still active
            if (this != mListener) {
                Log.d(TAG, "Client mode state change from previous manager");
                return;
            }

            Log.d(TAG, "State changed from client mode. state = " + state);

            if (state == WifiManager.WIFI_STATE_UNKNOWN) {
                // error while setting up client mode or an unexpected failure.
                mModeStateMachine.sendMessage(CMD_CLIENT_MODE_FAILED, this);
            } else if (state == WifiManager.WIFI_STATE_DISABLED) {
                // client mode stopped
                mModeStateMachine.sendMessage(CMD_CLIENT_MODE_STOPPED, this);
            } else if (state == WifiManager.WIFI_STATE_ENABLED) {
                // client mode is ready to go
                Log.d(TAG, "client mode active");
            } else {
                // only care if client mode stopped or started, dropping
            }
        }
    }

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

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

        updateBatteryStatsWifiState(true);
    }
    ...
}

这里的mManager是ActiveModeManager,是个接口,这里的ClientModeManager实现了这个接口。我们继续走下去,去看ClientModeManager,主要看mManager.start()这个调用。

2.6 frameworks/opt/net/wifi/service/java/com/android/server/wifi/ClientModeManager.java

/**
* Start client mode.
*/
public void start() {
    mStateMachine.sendMessage(ClientModeStateMachine.CMD_START);
}

ClientModeStateMachine也是个状态机,该状态机只有两个状态,初始状态为IdleState。

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

看一下初始状态Idlesate状态的处理

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;
    }
}

主要看 mWifiNative.setupInterfaceForClientMode的操作。

2.7 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;
    }
}

到这里就可以看到一些关键性的操作:

                         启动Hal:startHal()

                         启动supplicant:startSupplicant()

                         加载驱动(loadDriver):setupInterfaceForClientMode()

                         启动WifiMonitor:WifiMonitor.startMonitoring()

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

     这次的Wifi启动源码就讲到Android的java框架层,下次接着继续往下走流程:    

                HIDL—WPA适配层—wpa_supplicant—linux kernel 

    下面几层的简单说明:

3 HIDL

     Wifi到AndoidO之后不再使用jni,所以AndroidP也一样不再使用jni来实现Java代码与本地的C/C++代码交互,而是使用HIDL,Hardware Interface Define Language。

4 WPA适配层

      wpa_supplicant适配层是通用的wpa_supplicant的封装,在Android中作为WiFi部分的硬件抽象层来使用。wpa_supplicant适配层主要用于与wpa_supplicant守护进程的通信,以提供给Android框架使用,它实现了加载、控制和消息监控等功能。

5 wpa_supplicant

      wpa_supplicant是一个开源项目,已经被移植到Linux,Windows以及很多嵌入式系统上。它是WPA的应用层认证客户端,负责完成认证相关的登录、加密等工作。              

    wpa_supplicant是一个独立运行的守护进程,其核心是一个消息循环,在消息循环中处理WPA状态机、控制命令、驱动事件、配置信息等。wpa_supplicant有很多控制接口,也提供命令行和通行界面的控制模式:而Android与wpa_supplicant的通信通过Socket完成。

         这个工程中的内容编译后主要结果是生成动态库libwpa_client.so和可执行程序wpa_supplicant。

6 Linux Kernel

Wifi的内核驱动程序。

四 总结

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

猜你喜欢

转载自blog.csdn.net/weixin_42093428/article/details/80822632