zoukankan      html  css  js  c++  java
  • 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
    ");
            }
    
            /*
            * 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激活。

  • 相关阅读:
    Mysql设置字段唯一,值唯一方式
    在tomcat中模块化部署项目
    优化Eclipse
    akka 服务的搭建
    ES6中的let和var区别
    jquery,$,选择器,正则表达式
    jsp页面用java代码取随机数
    为什么要做权限管理
    将字符串编码成数值,求数值最大和问题
    Cookie与Session的区别
  • 原文地址:https://www.cnblogs.com/hunaiquan/p/5391363.html
Copyright © 2011-2022 走看看