Android WiFi激活过程

1. 从Settings开始

1.1 Settings的UI

上图的效果是有Settings的布局管理文件settings_headers.xml控制的,位置:packages/apps/Settings/res/xml/settings_headers.xml

    <!-- WIRELESS and NETWORKS -->
    <header android:id="@+id/wireless_section"
        android:title="@string/header_category_wireless_networks" />

    <!-- Wifi -->
    <header
        android:id="@+id/wifi_settings"
        android:fragment="com.android.settings.wifi.WifiSettings"
        android:title="@string/wifi_settings_title"
        android:icon="@drawable/ic_settings_wireless" />


    <!-- Ethernet -->
    <header
        android:id="@+id/ethernet_settings"
        android:fragment="com.android.settings.ethernet.EthernetSettings"
        android:title="@string/ethernet_settings_title"
        android:icon="@drawable/ic_settings_ethernet" />

1.2 Activity

com.android.settings.Settings.java 这个activity 是通过回调onBuildHeaders方法来加载进入应用之后的第一个布局文件的:

    public void onBuildHeaders(List<Header> headers) {
        if (!onIsHidingHeaders()) {
            loadHeadersFromResource(R.xml.settings_headers, headers);
            updateHeaderList(headers);
        }
    }

那么每一个header 是如果响应点击操作的呢.这个就要看Setting.java的onHeaderClick 方法了, onHeaderClick 方法会调用父类的onHeaderClick方法来打开相关的应用,其父类是根据我们配置在settings_headers.xml里面的 fragment和intent 来打开相对应的activity的.

public class Settings extends PreferenceActivity
        implements ButtonBarHandler, OnAccountsUpdateListener {
    @Override
    public void onHeaderClick(Header header, int position) {
        boolean revert = false;
        if (header.id == R.id.account_add) {
            revert = true;
        }

        super.onHeaderClick(header, position);

        if (revert && mLastHeader != null) {
            highlightHeader((int) mLastHeader.id);
        } else {
            mLastHeader = header;
        }
    }

}

frameworks/base/core/java/android/preference/PreferenceActivity.java

    public void onHeaderClick(Header header, int position) {
        if (header.fragment != null) {
            if (mSinglePane) {
                int titleRes = header.breadCrumbTitleRes;
                int shortTitleRes = header.breadCrumbShortTitleRes;
                if (titleRes == 0) {
                    titleRes = header.titleRes;
                    shortTitleRes = 0;
                }
                startWithFragment(header.fragment, header.fragmentArguments, null, 0,
                        titleRes, shortTitleRes);
            } else {
                switchToHeader(header);
            }
        } else if (header.intent != null) {
            startActivity(header.intent);
        }
    }

点击后启动WifiSettings Activity,WifiSettings中onActivityCreated方法会获取WifiManager的控制句柄,并把控制WiFi开关的Switch与WifiEnabler关联起来,代码如下:

        // On/off switch is hidden for Setup Wizard
        if (!mSetupWizardMode) {
            Switch actionBarSwitch = new Switch(activity);

            if (activity instanceof PreferenceActivity) {
                PreferenceActivity preferenceActivity = (PreferenceActivity) activity;
                if (preferenceActivity.onIsHidingHeaders() || !preferenceActivity.onIsMultiPane()) {
                    final int padding = activity.getResources().getDimensionPixelSize(
                            R.dimen.action_bar_switch_padding);
                    actionBarSwitch.setPaddingRelative(0, 0, padding, 0);
                    activity.getActionBar().setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM,
                            ActionBar.DISPLAY_SHOW_CUSTOM);
                    activity.getActionBar().setCustomView(actionBarSwitch, new ActionBar.LayoutParams(
                            ActionBar.LayoutParams.WRAP_CONTENT,
                            ActionBar.LayoutParams.WRAP_CONTENT,
                            Gravity.CENTER_VERTICAL | Gravity.END));
                }
            }

            mWifiEnabler = new WifiEnabler(activity, actionBarSwitch);
        }

android/packages/apps/Settings/src/com/android/settings/wifi/WifiEnabler.java

public class WifiEnabler implements CompoundButton.OnCheckedChangeListener  {
    public WifiEnabler(Context context, Switch switch_) {
        mContext = context;
        mSwitch = switch_;

        mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
        mIntentFilter = new IntentFilter(WifiManager.WIFI_STATE_CHANGED_ACTION);
        // The order matters! We really should not depend on this. :(
        mIntentFilter.addAction(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION);
        mIntentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
    }
    public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
        //Do nothing if called as a result of a state machine event
        if (mStateMachineEvent) {
            return;
        }
        // Show toast message if Wi-Fi is not allowed in airplane mode
        if (isChecked && !WirelessSettings.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/listenenr loop.
            buttonView.setChecked(false);
            return;
        }

        // Disable tethering if enabling Wifi
        int wifiApState = mWifiManager.getWifiApState();
        if (isChecked && ((wifiApState == WifiManager.WIFI_AP_STATE_ENABLING) ||
                (wifiApState == WifiManager.WIFI_AP_STATE_ENABLED))) {
            mWifiManager.setWifiApEnabled(null, false);
        }

        mSwitch.setEnabled(false);
        if (!mWifiManager.setWifiEnabled(isChecked)) {
            // Error
            mSwitch.setEnabled(true);
            Toast.makeText(mContext, R.string.wifi_error, Toast.LENGTH_SHORT).show();
        }
    }

}

由于WifiEnabler实现了CompoundButton.OnCheckedChangeListener,onCheckedChanged()会在按钮选中状态发生改变时被调用,即打开或关闭WiFi时调用此函数。

通过调用WifiManager.setWifiEnabled()实现打开动作。

2. 进入Android frameworks

frameworks/base/wifi/java/android/net/wifi/WifiManager.java

public class WifiManager {
    IWifiManager mService;

    public WifiManager(Context context, IWifiManager service) {
        mContext = context;
        mService = service;
        init();
    }


    public boolean setWifiEnabled(boolean enabled) {
        try {
            return mService.setWifiEnabled(enabled);
        } catch (RemoteException e) {
            return false;
        }
    }

}

 通过AIDL调用,实际调用的是 WifiService的setWifiEnabled 函数

frameworks/base/services/java/com/android/server/wifi/WifiService.java

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

 frameworks/base/services/java/com/android/server/wifi/WifiController.java

class WifiController extends StateMachine {
    WifiController(Context context, WifiService service, Looper looper) {
        super(TAG, looper);
        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 (isWifiEnabled && isScanningAlwaysAvailable) {
            setInitialState(mStaDisabledWithScanState);
        } else {
            setInitialState(mApStaDisabledState);
        }

} }

初始状态为ApStaDisabledState,当收到CMD_WIFI_TOGGLED消息后,状态会转换到DeviceActiveState。

 

   class ApStaDisabledState extends State {
        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;
        }
        public boolean processMessage(Message msg) {
            switch (msg.what) {
                case CMD_WIFI_TOGGLED:
                case CMD_AIRPLANE_TOGGLED:
                    if (mSettingsStore.isWifiToggleEnabled()) {
                        if (doDeferEnable(msg)) {
                            if (mHaveDeferredEnable) {
                                mDeferredEnableSerialNumber++;
                            }
                            mHaveDeferredEnable = !mHaveDeferredEnable;
                            break;
                        }
                        if (mDeviceIdle == false) {
                            transitionTo(mDeviceActiveState);
                        } else {
                            checkLocksAndTransitionWhenDeviceIdle();
                        }
                    }
                    break;
         ...........
}

由于DeviceActiveState的父状态为StaEnabledState,所以在有ApStaDisabledState进入DeviceActiveState时,会先进入StaEnabledState,然后再进入DeviceActiveState。因此,先调用StaEnabledState的enter():

    class StaEnabledState extends State {
        @Override
        public void enter() {
            mWifiStateMachine.setSupplicantRunning(true);
        }
        public boolean processMessage(Message msg) {
            switch (msg.what) {
        }

}

然后再调用DeviceActiveState的enter():

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

frameworks/base/wifi/java/android/net/wifi/WifiStateMachine.java

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

此时WiFi状态机为初始状态InitialState,处理CMD_START_SUPPLICANT的动作:

    class InitialState extends State {
       public boolean processMessage(Message message) {
            switch (message.what) {
                case CMD_START_SUPPLICANT:
                     if (mWifiNative.loadDriver()) {//加载驱动
                        try {
                            mNwService.wifiFirmwareReload(mInterfaceName, "STA");//download firmware
                        } 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);
                        }
                        mWifiMonitor.killSupplicant(mP2pSupported);
                        if(mWifiNative.startSupplicant(mP2pSupported)) {//重启WPA
                            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;

    }

WifiNative通过JNI调用 wifi.c,加载WiFi驱动,加载成功后会创建网络接口wlan0,然后启动wpa_supplicant。都启动成功后界面上会显示WiFi激活。

 

posted @ 2016-04-14 19:11  蝴蝶泉  阅读(3526)  评论(0编辑  收藏  举报