Android 8.1 settings中热点流程分析

Android提供了多种网络链接通道,最常见的是WIFI和移动基站通信(Cellular),另外还可将终端本身作为热点(Wifi Access Point),也可通过WIFI进行将两个终端直接进行连接(Wifi P2P),从而交互数据;同时还支持蓝牙将WIFI作为数据热点(Access Point),为其他设备提供网络接入。

对于移动通信,不同的运营商提供了不同的服务,网络提供的服务能力也各不相同。那么,Android是如何区分网络的承载能力的?为了区分不同网络的承载能力,Android提供了多达20种网络能力用以区分网络数据的接入方式(以下只列举常见的类型):

  • NET_CAPABILITY_MMS: Multimedia Messaging Service,表示网络可以通过MMSC发送MMS(彩信);
  • NET_CAPABILITY_SUPL: Secure User Plane Location,网络可以使用基站进行辅助GPS定位;
  • NET_CAPABILITY_DUN : Dial-Up Network,网络支持拨号的方式接入
  • NET_CAPABILITY_FOTA : Firmware Over The Air,网络可以使用FOTA服务器进行软件升级;
  • NET_CAPABILITY_IMS : IP Multimedia Subsystem, 网络可以使用多媒体系统服务
  • NET_CAPABILITY_CBS : Cell BroadCast Messaging, 网络可以接收基站广播消息
  • NET_CAPABILITY_WIFI_P2P:Wifi Peer to Peer(Wifi Direct),网络支持WIFI直连
  • NET_CAPABILITY_INTERNET:网络支持互联网访问
     

ConnectivityManager常用接口
ConnectivityManager提供了很多接口用于获取系统当前的网络连接信息:

  • getAllNetworkInfo(): 返回所有网络信息
  • getActiveNetworkInfo():获取当前激活的网络连接信息
  • getNetworkForType: 获取指定类型的网络
  • requestNetwork(...) : 请求建立某种类型的网络
  • setAirplaneMode(): 开启飞行模式
  • addDefaultNetworkActiveListener() : 监听默认网络连接是否激活
  • registerNetworkCallback() : 监听某个网络请求的状态,可用时进行回调
     

它主要涉及的类有TetherSettings.java 、WifiApEnabler.java、WifiStateMachine.java以及它的布局文件tether_prefs.xml

首先从布局文件tether_prefs.xml分析



    

    

    

    

    

    

 

key="enable_wifi_ap"就是代表热点开关,根据key值我们转到布局文件所在的类TetherSettings.java。

 

初始化

addPreferencesFromResource(R.xml.tether_prefs);
...
mEnableWifiAp =(SwitchPreference) findPreference(ENABLE_WIFI_AP);

 

监听开关状态改变

    private WifiApEnabler mWifiApEnabler;
    //将开关和WifiApEnabler绑定,在WifiApEnabler中进行开关的状态更新
    mWifiApEnabler = new WifiApEnabler(activity, mDataSaverBackend, mEnableWifiAp);

    @Override
    public void onStart() {
    ...
        if (mWifiApEnabler != null) {
            mEnableWifiAp.setOnPreferenceChangeListener(this);
            mWifiApEnabler.resume();
        }
    }

    @Override
    public boolean onPreferenceChange(Preference preference, Object value) {
        boolean enable = (Boolean) value;

        if (enable) {
            startTethering(TETHERING_WIFI);
        } else {
            mCm.stopTethering(TETHERING_WIFI);
        }
        return false;
    }

继续跟踪,热点状态改变

private class TetherChangeReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context content, Intent intent) {
            String action = intent.getAction();
        if (action.equals(ConnectivityManager.ACTION_TETHER_STATE_CHANGED)) {
        ...
            startTethering(TETHERING_WIFI);
        } else if (action.equals(WifiManager.WIFI_AP_STATE_CHANGED_ACTION)) {
                int state = intent.getIntExtra(WifiManager.EXTRA_WIFI_AP_STATE, 0);
                if (state == WifiManager.WIFI_AP_STATE_DISABLED
                        && mRestartWifiApAfterConfigChange) {
                    mRestartWifiApAfterConfigChange = false;
                    Log.d(TAG, "Restarting WifiAp due to prior config change.");
                    startTethering(TETHERING_WIFI);
                }
         }
            ...//热点状态变化/连接方式参数变化都会导致startTethering()
            //顺便更新USB和BT连接的状态
}

 

有接收就有发送,发送广播的是WifiStateMachine.java,它在frameworks目录下

 

private void setWifiApState(int wifiApState, int reason, String ifaceName, int mode) {
    final int previousWifiApState = mWifiApState.get();  
    ...    
    final Intent intent = new Intent(WifiManager.WIFI_AP_STATE_CHANGED_ACTION);
        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
        intent.putExtra(WifiManager.EXTRA_WIFI_AP_STATE, wifiApState);
        intent.putExtra(WifiManager.EXTRA_PREVIOUS_WIFI_AP_STATE, previousWifiApState);
        if (wifiApState == WifiManager.WIFI_AP_STATE_FAILED) {
            //only set reason number when softAP start failed
            intent.putExtra(WifiManager.EXTRA_WIFI_AP_FAILURE_REASON, reason);
        }

        intent.putExtra(WifiManager.EXTRA_WIFI_AP_INTERFACE_NAME, ifaceName);
        intent.putExtra(WifiManager.EXTRA_WIFI_AP_MODE, mode);

        mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
}

另外,在设置的dialog中获取用户设置的信息

    public WifiConfiguration getConfig() {

        WifiConfiguration config = new WifiConfiguration();

        /**
         * TODO: SSID in WifiConfiguration for soft ap
         * is being stored as a raw string without quotes.
         * This is not the case on the client side. We need to
         * make things consistent and clean it up
         */
        config.SSID = mSsid.getText().toString();

        config.apBand = mBandIndex;

        switch (mSecurityTypeIndex) {
            case OPEN_INDEX:
                config.allowedKeyManagement.set(KeyMgmt.NONE);
                return config;

            case WPA2_INDEX:
                config.allowedKeyManagement.set(KeyMgmt.WPA2_PSK);
                config.allowedAuthAlgorithms.set(AuthAlgorithm.OPEN);
                if (mPassword.length() != 0) {
                    String password = mPassword.getText().toString();
                    config.preSharedKey = password;
                }
                return config;
        }
        return null;
    }

在TetherSettings.java中实现保存并生效

    public void onClick(DialogInterface dialogInterface, int button) {
        if (button == DialogInterface.BUTTON_POSITIVE) {
            mWifiConfig = mDialog.getConfig();
            if (mWifiConfig != null) {
                /**
                 * if soft AP is stopped, bring up
                 * else restart with new config
                 * TODO: update config on a running access point when framework support is added
                 */
                if (mWifiManager.getWifiApState() == WifiManager.WIFI_AP_STATE_ENABLED) {
                    Log.d("TetheringSettings",
                            "Wifi AP config changed while enabled, stop and restart");
                    mRestartWifiApAfterConfigChange = true;
                    mCm.stopTethering(TETHERING_WIFI);
                }
                mWifiManager.setWifiApConfiguration(mWifiConfig);
                int index = WifiApDialog.getSecurityTypeIndex(mWifiConfig);
                mCreateNetwork.setSummary(String.format(getActivity().getString(CONFIG_SUBTEXT),
                        mWifiConfig.SSID,
                        mSecurityType[index]));
            }
        }
    }


 

你可能感兴趣的:(Wifi)