Wifi启动流程分析

      因工作需要,对Android的Wifi模块做了些分析与跟踪,当前的源码版本是Android 4.4的,在Android 5以后已经发生了一些变化。

从Android的启动开始

      进入Android的入口是SystemServer,在这里面注册了许多的Service。这里主要看与Wifi相关的服务。

try {
    Slog.i(TAG, "Wi-Fi Service");
    wifi = new WifiService(context);
    ServiceManager.addService(Context.WIFI_SERVICE, wifi);
} catch (Throwable e) {
    reportWtf("starting Wi-Fi Service", e);
}

try {
    Slog.i(TAG, "Connectivity Service");
    connectivity = new ConnectivityService(
            context, networkManagement, networkStats, networkPolicy);
    ServiceManager.addService(Context.CONNECTIVITY_SERVICE, connectivity);
    networkStats.bindConnectivityManager(connectivity);
    networkPolicy.bindConnectivityManager(connectivity);

    wifiP2p.connectivityServiceReady();
    wifi.checkAndStartWifi();
} catch (Throwable e) {
    reportWtf("starting Connectivity Service", e);
}

上述代码中,初始化了wifiService,并把这两个对象加到ServiceManager上,接着又创建了ConnectivityService对象,然后通过创建的WiFiService对象调用wifi.checkAndStartWifi();用于初始化开机时的wifi状态。

先说说WifiService

进入到WifiService.java的构造方法中,路径:
/frameworks/base/services/java/com/android/server/wifi/WifiService.java

public WifiService(Context context) {
    mContext = context;
    mInterfaceName =  SystemProperties.get("wifi.interface", "wlan0");
    mWifiStateMachine = new WifiStateMachine(mContext, mInterfaceName);
    mWifiStateMachine.enableRssiPolling(true);
    mBatteryStats = BatteryStatsService.getService();
    mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE);
    mNotificationController = new WifiNotificationController(mContext, mWifiStateMachine);
    mTrafficPoller = new WifiTrafficPoller(mContext, mInterfaceName);
    mSettingsStore = new WifiSettingsStore(mContext);
    HandlerThread wifiThread = new HandlerThread("WifiService");
    wifiThread.start();
    mClientHandler = new ClientHandler(wifiThread.getLooper());
    mWifiStateMachineHandler = new WifiStateMachineHandler(wifiThread.getLooper());
    mWifiController = new WifiController(mContext, this, wifiThread.getLooper());
    mWifiController.start();
    mBatchedScanSupported = mContext.getResources().getBoolean(
            R.bool.config_wifi_batched_scan_supported);
    registerForScanModeChange();
    mContext.registerReceiver(
            new BroadcastReceiver() {
                @Override
                public void onReceive(Context context, Intent intent) {
                    if (mSettingsStore.handleAirplaneModeToggled()) {
                        mWifiController.sendMessage(CMD_AIRPLANE_TOGGLED);
                    }
                }
            },
            new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED));
    // Adding optimizations of only receiving broadcasts when wifi is enabled
    // can result in race conditions when apps toggle wifi in the background
    // without active user involvement. Always receive broadcasts.
    registerForBroadcasts();
}

这里可以看到,首先读取系统属性,获取系统wifi.interface,默认为wlan0。主要看这两句:

mWifiStateMachine =new WifiStateMachine(mContext,mInterfaceName);
mWifiStateMachine.enableRssiPolling(true);

      可以看到,在实例化WifiService的时候,先创建了一个Wifi状态机对象,然后开始Rssi轮询。然后新建一个HandlerThread来处理所有的Message,并注册一些Broadcast的接收者。接着又创建了一个mWifiController 。(【注】:其实自己之前看到这里的时候也在想,为什么这么麻烦?先搞了一个Wifi状态机(哈哈,以前听到状态机,感觉感觉蛮高大上的样子),然后又弄了个WifiController又是干嘛的。)

      其实,WifiStateMachine用于控制整个Wifi的开启、关闭、连接和断开等各个状态的切换,这个感觉还是比较复杂的,后面再说吧。不过还是先看看它的构造方法做了些什么:源码路径在:/frameworks/base/wifi/java/android/net/wifi/WifiStateMachine.java
这个构造方法太长了,截取一段比较关键的:

mWifiNative = new WifiNative(mInterfaceName);
mWifiConfigStore = new WifiConfigStore(context, mWifiNative);
mWifiMonitor = new WifiMonitor(this, mWifiNative);
mWifiInfo = new WifiInfo();
mSupplicantStateTracker = new SupplicantStateTracker(context, this, mWifiConfigStore, getHandler());
mLinkProperties = new LinkProperties();
mNetlinkLinkProperties = new LinkProperties();

这里初始化了一些对象,都是与wifi的控制相关的信息。

addState(mDefaultState);
addState(mInitialState, mDefaultState);
addState(mSupplicantStartingState, mDefaultState);
addState(mSupplicantStartedState, mDefaultState);
    addState(mDriverStartingState, mSupplicantStartedState);
    addState(mDriverStartedState, mSupplicantStartedState);
        addState(mScanModeState, mDriverStartedState);
        addState(mConnectModeState, mDriverStartedState);
            addState(mL2ConnectedState, mConnectModeState);
                addState(mObtainingIpState, mL2ConnectedState);
                addState(mVerifyingLinkState, mL2ConnectedState);
                addState(mCaptivePortalCheckState, mL2ConnectedState);
                addState(mConnectedState, mL2ConnectedState);
            addState(mDisconnectingState, mConnectModeState);
            addState(mDisconnectedState, mConnectModeState);
            addState(mWpsRunningState, mConnectModeState);
    addState(mWaitForP2pDisableState, mSupplicantStartedState);
    addState(mDriverStoppingState, mSupplicantStartedState);
    addState(mDriverStoppedState, mSupplicantStartedState);
addState(mSupplicantStoppingState, mDefaultState);
addState(mSoftApStartingState, mDefaultState);
addState(mSoftApStartedState, mDefaultState);
    addState(mTetheringState, mSoftApStartedState);
    addState(mTetheredState, mSoftApStartedState);
    addState(mUntetheringState, mSoftApStartedState);

setInitialState(mInitialState);

setLogRecSize(2000);
setLogOnlyTransitions(false);
if (DBG) setDbg(true);

//start the state machine
start();

这里可以看到,WifiStateMachine在实例化的时候,往状态机中添加了许许多多的状态,在wifi连接与断开的整个流程中,都会与上述添加的状态息息相关。添加完这些状态后,先是设置了一下wifi状态机的最初始状态为InitialState。然后调用start()方法启动wifi状态机工作,这个start()方法的实现在WifiStateMachine的父类StateMachine中,所以状态机也叫层次状态机。
    由上面的分析,知道了在WifiService初始化的时候,实例化了一个WifiStateMachine,然后由WifiStateMachine接管了整个Wifi运行时期各种状态变化的管理。
      不过,在WifiService的构造方法中,还实例化了一个WifiController对象,这个又是在干嘛呢?来看看它在实例化的时候做了些什么:
/frameworks/base/services/java/com/android/server/wifi/WifiController.java

WifiController(Context context, WifiService service, Looper looper) {
        super(TAG, looper);
        mContext = context;
        mWifiStateMachine = service.mWifiStateMachine;
        mSettingsStore = service.mSettingsStore;
        mLocks = service.mLocks;

        mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
        Intent idleIntent = new Intent(ACTION_DEVICE_IDLE, null);
        mIdleIntent = PendingIntent.getBroadcast(mContext, IDLE_REQUEST, idleIntent, 0);

        addState(mDefaultState);
            addState(mApStaDisabledState, mDefaultState);
            addState(mStaEnabledState, mDefaultState);
                addState(mDeviceActiveState, mStaEnabledState);
                addState(mDeviceInactiveState, mStaEnabledState);
                    addState(mScanOnlyLockHeldState, mDeviceInactiveState);
                    addState(mFullLockHeldState, mDeviceInactiveState);
                    addState(mFullHighPerfLockHeldState, mDeviceInactiveState);
                    addState(mNoLockHeldState, mDeviceInactiveState);
            addState(mStaDisabledWithScanState, mDefaultState);
            addState(mApEnabledState, mDefaultState);
            addState(mEcmState, mDefaultState);
        if (mSettingsStore.isScanAlwaysAvailable()) {
            setInitialState(mStaDisabledWithScanState);
        } else {
            setInitialState(mApStaDisabledState);
        }
        setLogRecSize(100);
        setLogOnlyTransitions(false);

        IntentFilter filter = new IntentFilter();
        filter.addAction(ACTION_DEVICE_IDLE);
        filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
        mContext.registerReceiver(
                new BroadcastReceiver() {
                    @Override
                    public void onReceive(Context context, Intent intent) {
                        String action = intent.getAction();
                        if (action.equals(ACTION_DEVICE_IDLE)) {
                            sendMessage(CMD_DEVICE_IDLE);
                        } else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
                            mNetworkInfo = (NetworkInfo) intent.getParcelableExtra(
                                    WifiManager.EXTRA_NETWORK_INFO);
                        }
                    }
                },
                new IntentFilter(filter));

        initializeAndRegisterForSettingsChange(looper);
}

这段代码好长,感觉贴图上来好难看。。。
不过可以大致看到,在WifiService中把WifiStateMachine的实例传了进来。这里也注册了好几种状态,是的,WifiController也继承自StateMachine,并且在实例化的时候设置了初始状态。如下,当wifi被设置为一直可以扫描的话,初始状态会设置为mStaDisabledWithScanState,一般会走else分支。

if (mSettingsStore.isScanAlwaysAvailable()) {
     setInitialState(mStaDisabledWithScanState);
} else {
     setInitialState(mApStaDisabledState);
}

在WifiService中创建该实例后,立即调用了mWifiController.start();根据刚才对WiFiStateMachine的分析可知,这里调用的是状态机父类StateMachine中的start()方法。调用start方法后,WifiController首先进入mDefaultState状态,然后进入mApStaDisabledState状态(为什么呢?从addState(mApStaDisabledState, mDefaultState);可以看出,mDefaultState是mApStaDisabledState的父状态,执行的时候,会先进入父状态的enter(),然后再执行子状态。【层次状态机】),此时,WifiController状态机的状态为mApStaDisabledState状态,进入到该状态的enter()方法:

@Override
public void enter() {
     mWifiStateMachine.setSupplicantRunning(false);
     // Supplicant can't restart right away, so not the time we switched off
     mDisabledTimestamp = SystemClock.elapsedRealtime();
     mDeferredEnableSerialNumber++;
     mHaveDeferredEnable = false;
}

发现做了些配置,没有更多的动作,到这里WifiService的初始化大致做完了,还有一些细节,留到以后再分析吧。

回到SystemServer

在本文开始的时候,有贴过一段代码,其中在初始化完WifiService和ConnectivityService后,执行了如下代码:

    wifi.checkAndStartWifi();

这句代码才开始真正从开机状态完成真正的wifi监测与打开的动作。

public void checkAndStartWifi() {
        //检查WiFi是否需要使能
        boolean wifiEnabled = mSettingsStore.isWifiToggleEnabled();
        Slog.i(TAG, "WifiService starting up with Wi-Fi " +
                (wifiEnabled ? "enabled" : "disabled"));

        // If we are already disabled (could be due to airplane mode), avoid changing persist
        // state here
        // MStar Android Patch Begin
        if (wifiEnabled) {
            setWifiEnabled(wifiEnabled);
        } else {
            //如果Wifi本身没有启动,测试softap是否需要启动
            boolean wifiApEnabled = mSettingsStore.isWifiApToggleEnabled();
            if (wifiApEnabled) {
                Slog.d(TAG, "wifi ap start with enabled");
                setWifiApEnabled(null, wifiApEnabled);
            } else {
                Slog.d(TAG, "wifi ap start with disabled");
            }
        }
        // MStar Android Patch End
        mWifiWatchdogStateMachine = WifiWatchdogStateMachine.makeWifiWatchdogStateMachine(mContext);
}

上述实现WifiService.java中,首先来看这句:

 boolean wifiEnabled = mSettingsStore.isWifiToggleEnabled();

先读取系统上次关机时的wifi开关状态,如果该值为true,证明上次是打开的,那么执行如下代码:

setWifiEnabled(wifiEnabled);

来看这句代码的实现:

public synchronized boolean setWifiEnabled(boolean enable) {
        enforceChangePermission();
        Slog.d(TAG, "setWifiEnabled: " + enable + " pid=" + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid());
        if (DBG) {
            Slog.e(TAG, "Invoking mWifiStateMachine.setWifiEnabled\n");
        }

        /*
        * 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);
        }

        mWifiController.sendMessage(CMD_WIFI_TOGGLED);
        return true;
}

关键是最后一句:mWifiController.sendMessage(CMD_WIFI_TOGGLED);
给WifiController发了个消息:CMD_WIFI_TOGGLED。又转到了WifiController中 :)

刚才前面已经分析过,当wifiController的初始化状态为:ApStaDisabledState。所以,当前这个消息将由该状态来处理,来看它的processMessage()方法:

public boolean processMessage(Message msg) {
    switch (msg.what) {
        case CMD_WIFI_TOGGLED:
        case CMD_AIRPLANE_TOGGLED:
            if (mSettingsStore.isWifiToggleEnabled()) {
                if (doDeferEnable(msg)) {
                    if (mHaveDeferredEnable) {
                        //  have 2 toggles now, inc serial number an ignore both
                        mDeferredEnableSerialNumber++;
                    }
                    mHaveDeferredEnable = !mHaveDeferredEnable;
                    break;
                }
                if (mDeviceIdle == false) {
                    transitionTo(mDeviceActiveState);
                } else {
                    checkLocksAndTransitionWhenDeviceIdle();
                }
            }
            break;
        ....
        default:
            return NOT_HANDLED;
    }
    return HANDLED;
}

这里可以看到,当系统wifi打开,并且mDeviceIdle == false,则会执行状态转换:

transitionTo(mDeviceActiveState);

addState(mDeviceActiveState, mStaEnabledState);可知,mStaEnabledState是mDeviceActiveState的父状态,所以先执行其enter()方法,

class StaEnabledState extends State {
    @Override
    public void enter() {
        mWifiStateMachine.setSupplicantRunning(true);
    }
    ...
}

这里执行了WifiStateMachine的setSupplicantRunning方法。

public void setSupplicantRunning(boolean enable) {
    if (enable) {
        sendMessage(CMD_START_SUPPLICANT);
    } else {
        sendMessage(CMD_STOP_SUPPLICANT);
    }
}

可以看到,这里又发了消息:CMD_START_SUPPLICANT。前面分析WiFiStateMachine初始化的时候,已经说过,其初始化状态为InitialState,所以这个消息将由它的processMessage()方法来处理:

case CMD_START_SUPPLICANT:
    if (mWifiNative.loadDriver()) {
        try {
            mNwService.wifiFirmwareReload(mInterfaceName, "STA");
        } catch (Exception e) {
            loge("Failed to reload STA firmware " + e);
            // continue
        }

        try {
            // A runtime crash can leave the interface up and
            // this affects connectivity when supplicant starts up.
            // Ensure interface is down before a supplicant start.
            mNwService.setInterfaceDown(mInterfaceName);
            // Set privacy extensions
            mNwService.setInterfaceIpv6PrivacyExtensions(mInterfaceName, true);

           // IPv6 is enabled only as long as access point is connected since:
           // - IPv6 addresses and routes stick around after disconnection
           // - kernel is unaware when connected and fails to start IPv6 negotiation
           // - kernel can start autoconfiguration when 802.1x is not complete
            mNwService.disableIpv6(mInterfaceName);
        } catch (RemoteException re) {
            loge("Unable to change interface settings: " + re);
        } catch (IllegalStateException ie) {
            loge("Unable to change interface settings: " + ie);
        }

       /* Stop a running supplicant after a runtime restart
        * Avoids issues with drivers that do not handle interface down
        * on a running supplicant properly.
        */
        mWifiMonitor.killSupplicant(mP2pSupported);
        if(mWifiNative.startSupplicant(mP2pSupported)) {
            setWifiState(WIFI_STATE_ENABLING);
            if (DBG) log("Supplicant start successful");
            mWifiMonitor.startMonitoring();
            transitionTo(mSupplicantStartingState);
        } else {
            loge("Failed to start supplicant!");
        }
    } else {
        loge("Failed to load driver");
    }
    break;

这一段代码还是比较关键的,可以看到首先通过mWifiNative.loadDriver()去加载驱动,当驱动加载成功后,重新加载固件:

mNwService.wifiFirmwareReload(mInterfaceName, "STA");
mNwService.setInterfaceDown(mInterfaceName)
...
setWifiState(WIFI_STATE_ENABLING);
mWifiMonitor.startMonitoring();
transitionTo(mSupplicantStartingState);
...

做了一系列的配置操作,设置wifi状态为WIFI_STATE_ENABLING正在打开,开始监管startMonitoring(),最后把状态转移到mSupplicantStartingState。

看完父状态的操作,再来看mDeviceActiveState的enter方法:

class DeviceActiveState extends State {
    @Override
    public void enter() {
    mWifiStateMachine.setOperationalMode(WifiStateMachine.CONNECT_MODE);
        mWifiStateMachine.setDriverStart(true);
        mWifiStateMachine.setHighPerfModeEnabled(false);
    }
    ...
}

可以看到,这里都是在通过wifi状态机去做一系列的操作,比如设置连接模式,启动driver等,来看看

mWifiStateMachine.setDriverStart(true);

看看它的实现:

public void setDriverStart(boolean enable) {
    if (enable) {
         sendMessage(CMD_START_DRIVER);
    } else {
         sendMessage(CMD_STOP_DRIVER);
    }
}

这里由刚才分析的结果,WiFiStateMachine进入了mSupplicantStartingState状态,所以,这个消息将由它的方法去处理,再经过几次状态转换到SupplicantStartedState,driver就启动了。

你可能感兴趣的:(Android)