android 系统数据业务---模式

来源:互联网 发布:淘宝确认收货时间 编辑:程序博客网 时间:2024/05/16 09:03

转自 http://blog.csdn.net/u012439416/article/details/75267191

4 数据业务模式

在手机以及模块中,移动/联通/电信的信号都会有类似下面的2G/3G/4G切换,

       图一 信号模式切换图

这些值的定义都在RILConstants.java中,如下,

[html] view plain copy
  1. /* NETWORK_MODE_* See ril.h RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE */  
  2. int NETWORK_MODE_WCDMA_PREF = 0; /* GSM/WCDMA (WCDMA preferred) */  
  3. int NETWORK_MODE_GSM_ONLY   = 1; /* GSM only */  
  4. int NETWORK_MODE_WCDMA_ONLY  = 2; /* WCDMA only */  
  5. int NETWORK_MODE_GSM_UMTS   = 3; /* GSM/WCDMA (auto mode, according to PRL)  
  6. int NETWORK_MODE_CDMA       = 4; /* CDMA and EvDo (auto mode, according to PRL)  
  7. int NETWORK_MODE_CDMA_NO_EVDO   = 5; /* CDMA only */  
  8. int NETWORK_MODE_EVDO_NO_CDMA   = 6; /* EvDo only */  
  9. int NETWORK_MODE_GLOBAL   = 7; /* GSM/WCDMA, CDMA, and EvDo*/                                              
  10. int NETWORK_MODE_LTE_CDMA_EVDO  = 8; /* LTE, CDMA and EvDo */  
  11. int NETWORK_MODE_LTE_GSM_WCDMA  = 9; /* LTE, GSM/WCDMA */  
  12. int NETWORK_MODE_LTE_CDMA_EVDO_GSM_WCDMA = 10;  
  13. /* LTE, CDMA, EvDo, GSM/WCDMA */  
  14. int NETWORK_MODE_LTE_ONLY     = 11; /* LTE Only mode. */  
  15. int NETWORK_MODE_LTE_WCDMA  = 12; /* LTE/WCDMA */  

当然,ril库中也会有对应值的定义。

2.1 数据网络模式默认值

在切换信号之前,首先看看android系统中信号的默认值。在加载完系统的SIM卡之后,然后才会设置信号的默认值。

主要流程图如下,

                                                   图二 获取数据网络默认值流程图

该流程图分为2个进程,左半部分为系统服务所在的进程,又半部分为phone进程。

主要的步骤如下,

1,android系统启动加载sim卡完成之后,发送ACTION_INTERNAL_SIM_STATE_CHANGED广播;

2, 系统服务所在的进程的SubscriptionInfoUpdater的构造方法中会注册该广播, sReceiver对该广播的处理如下,

[html] view plain copy
  1. else if (action.equals(IccCardProxy.ACTION_INTERNAL_SIM_STATE_CHANGED)) {  
  2.   if (IccCardConstants.INTENT_VALUE_ICC_LOCKED.equals(simStatus)) {//sim被锁  
  3.          String reason = intent.getStringExtra(  
  4.                         IccCardConstants.INTENT_KEY_LOCKED_REASON);  
  5.          sendMessage(obtainMessage(EVENT_SIM_LOCKED, slotId, -1, reason));  
  6.   } else if (IccCardConstants.INTENT_VALUE_ICC_LOADED.equals(simStatus)){//sim加载完  
  7.           sendMessage(obtainMessage(EVENT_SIM_LOADED, slotId, -1));//发送消息  
  8.   }  

3, 系统服务所在的进程处理完成之后,通过binder机制跨进程调用phone进程设置数据网络默认sim卡以及信号值。

PhoneFactory的calculatePreferredNetworkType方法如下,

[html] view plain copy
  1. public static int calculatePreferredNetworkType(Context context, int phoneSubId) {  
  2. int networkType = android.provider.Settings.Global.getInt(context.getContentResolver(),  
  3.          android.provider.Settings.Global.PREFERRED_NETWORK_MODE + phoneSubId,  
  4.                 RILConstants.PREFERRED_NETWORK_MODE);  
  5.     return networkType;  
  6. }  

当然,首先读取setting数据库中的PREFERRED_NETWORK_MODE 字段值,如果为空就设置RILConstants的

PREFERRED_NETWORK_MODE值。

在刚刷机时,该值肯定为空,只有在设置之后,信号值才会保存在PREFERRED_NETWORK_MODE 字段中。

也就是说,如果不是刷机启动,机器开机后会默认加载上次设置的值。

RILConstants的PREFERRED_NETWORK_MODE值如下,

[html] view plain copy
  1. int PREFERRED_NETWORK_MODE      = TelephonyManager  
  2.             .getDefaultPreferredNetworkType(0, NETWORK_MODE_WCDMA_PREF);  

TelephonyManager的getDefaultPreferredNetworkType方法如下,

[html] view plain copy
  1. public static int getDefaultPreferredNetworkType(int phoneId, int defaultValue) {  
  2.         String mode = getTelephonyProperty(phoneId, "ro.telephony.default_network", null);  
  3.         if (mode != null) {  
  4.             return Integer.parseInt(mode);  
  5.         }  
  6.         return defaultValue;  
  7.     }  

这2个方法的目的都是为设置数据网络信号值,

1,首先通过配置文件设置,android系统中一般都有设置,虽然设置的文件不同,但是语句完全一样,

[html] view plain copy
  1. ro.telephony.default_network=5  

2,如果配置文件未设置,就会在RILConstants中进行设置, getDefaultPreferredNetworkType方法第二个参数就是默认值。

当然,几乎所有的android基线都会采用第一种方法进行设置,因为这样可以根据不同的项目设置不同的配置文件,灵活度高。

2.2 开机数据网络设置

一般双卡手机开机时,会调用三次RIL的setPreferredNetworkType方法向modem发送

RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE消息设置数据网络。

2.2.1第一次设置

第一次设置比较容易,是在phone进程的RIL和ril守护进程连接之后,收到守护进程上报的RIL_UNSOL_RIL_CONNECTED

消息就直接设置网络制式,

[html] view plain copy
  1. case RIL_UNSOL_RIL_CONNECTED: {  
  2.      if (RILJ_LOGD) unsljLogRet(response, ret);  
  3. getRadioCapability(mSupportedRafHandler.obtainMessage());  
  4. // Initial conditions  
  5.            setRadioPower(false, null);  
  6.            setPreferredNetworkType(mPreferredNetworkType, null);  
  7.            setCdmaSubscriptionSource(mCdmaSubscription, null);  
  8.            setCellInfoListRate(Integer.MAX_VALUE, null);  
  9.            notifyRegistrantsRilConnectionChanged(((int[])ret)[0]);  
  10.            break;  
  11.  }  

mPreferredNetworkType的值是在RIL构造方法中赋值的,一般为系统的默认值。

2.2.2第二次设置

其实,第二次和第三次设置的过程完全一样,都在在SIM加载完设置SIM信息的时候调用的,间隔时间也很短.几秒钟甚至不到 1秒钟。

都是SubscriptionController里面的方法,例如setCarrierText, setIconTint, setMccMnc等等。

这些方法都是调用notifySubscriptionInfoChanged方法进行设置的,调用流程图如下,



整个过程比较简单直白,在TelephonyRegistry和ServiceStateTracker使用了一个简单的listener,

SstSubscriptionsChangedListener是ServiceStateTracker的内部类,继承于OnSubscriptionsChangedListener,

[html] view plain copy
  1. protected class SstSubscriptionsChangedListener extends OnSubscriptionsChangedListener {  

并且在ServiceStateTracker调用SubscriptionManager对象的addOnSubscriptionsChangedListener方法注册的,

最后调用TelephonyRegistry的addOnSubscriptionsChangedListener方法完成注册。

2.3设置界面的设置过程

图一 界面对应的代码为MobileNetworkSettings.java,数据网络设置的流程图如下,



重点分析以下三个点:

1,MobileNetworkSettings的onPreferenceChange方法,

MobileNetworkSettings的onPreferenceChange方法如下,

[html] view plain copy
  1. public boolean onPreferenceChange(Preference preference, Object objValue) {  
  2.    final int phoneSubId = mPhone.getSubId(); //获取卡槽  
  3.    if (preference == mButtonPreferredNetworkMode) {  
  4.       //NOTE onPreferenceChange seems to be called even if there is no change  
  5.       //Check if the button value is changed from the System.Setting  
  6.       mButtonPreferredNetworkMode.setValue((String) objValue);  
  7.       int buttonNetworkMode;  
  8.       buttonNetworkMode = Integer.valueOf((String) objValue).intValue();  
  9.       int settingsNetworkMode = android.provider.Settings.Global.getInt(  
  10.           mPhone.getContext().getContentResolver(),  
  11.           android.provider.Settings.Global.PREFERRED_NETWORK_MODE + phoneSubId,  
  12.                     preferredNetworkMode);//获取当前的数据网络模式  
  13.       if (buttonNetworkMode != settingsNetworkMode) {  
  14.             int modemNetworkMode;  
  15.             // if new mode is invalid ignore it  
  16.             switch (buttonNetworkMode) {  
  17.                case Phone.NT_MODE_WCDMA_PREF:  
  18.                case Phone.NT_MODE_GSM_ONLY:  
  19.                case Phone.NT_MODE_WCDMA_ONLY:  
  20.                case Phone.NT_MODE_GSM_UMTS:  
  21.                case Phone.NT_MODE_CDMA:  
  22.                case Phone.NT_MODE_CDMA_NO_EVDO:  
  23.                case Phone.NT_MODE_EVDO_NO_CDMA:  
  24.                case Phone.NT_MODE_GLOBAL:  
  25.                case Phone.NT_MODE_LTE_CDMA_AND_EVDO:  
  26.                case Phone.NT_MODE_LTE_GSM_WCDMA:  
  27.                case Phone.NT_MODE_LTE_CDMA_EVDO_GSM_WCDMA:  
  28.                case Phone.NT_MODE_LTE_ONLY:  
  29.                case Phone.NT_MODE_LTE_WCDMA:  
  30.                   // This is one of the modes we recognize  
  31.                   modemNetworkMode = buttonNetworkMode;  
  32.                   break;  
  33.                default:  
  34.                    return true;  
  35.        }  
  36. android.provider.Settings.Global.putInt(mPhone.getContext().getContentResolver(),  
  37.          android.provider.Settings.Global.PREFERRED_NETWORK_MODE + phoneSubId,  
  38.            buttonNetworkMode );// 保存到数据库中  
  39.                 //Set the modem network mode  
  40.  mPhone.setPreferredNetworkType(modemNetworkMode, mHandler  
  41.         .obtainMessage(MyHandler.MESSAGE_SET_PREFERRED_NETWORK_TYPE));  
  42.      }  
  43. }  

由此可见,主要步骤如下,

A,首先从数据库中获取上次的信号模式,如果和当前的值相等就没有设置的必要;

B,然后检查模式是否正确,将模式的值保存在设置数据库中;

C,调用PhoneProxy的setPreferredNetworkType方法设置网络模式。

其中需要注意的是MESSAGE_SET_PREFERRED_NETWORK_TYPE这个消息。

2.4 TelephonyManager设置

TelephonyManager是有phone进程有关的API接口,当然也可以进行网络设置,调用其setPreferredNetworkType方法就可以了,

当然需要添加MODIFY_PHONE_STATE权限,

调用流程图如下,


整个过程和数据业务的打开调用过程差不多。

TelephonyManager的 setPreferredNetworkType方法如下,

[html] view plain copy
  1. try {  
  2.     return getITelephony().setPreferredNetworkType(networkType);  
  3. }  

跨进程调用phone进程的PhoneInterfaceManager的setPreferredNetworkType方法,如下,

首先检查权限,

[html] view plain copy
  1. enforceModifyPermissionOrCarrierPrivilege();  

然后发送CMD_SET_PREFERRED_NETWORK_TYPE消息切换到主线程中执行,

[html] view plain copy
  1. Boolean success = (Boolean) sendRequest(CMD_SET_PREFERRED_NETWORK_TYPE, networkType, subId);  

如果切换成功,将切换后的值保存到数据库,

[html] view plain copy
  1. if (success) {  
  2.      Settings.Global.putInt(mPhone.getContext().getContentResolver(),  
  3.                Settings.Global.PREFERRED_NETWORK_MODE + subId, networkType);  
  4. }  

PhoneInterfaceManager对CMD_SET_PREFERRED_NETWORK_TYPE消息处理如下,

[html] view plain copy
  1. request = (MainThreadRequest) msg.obj;  
  2. onCompleted = obtainMessage(EVENT_SET_PREFERRED_NETWORK_TYPE_DONE, request);  
  3. int networkType = (Integer) request.argument;  
  4. getPhoneFromRequest(request).setPreferredNetworkType(networkType, onCompleted);  
  5. break;  

首先封装EVENT_SET_PREFERRED_NETWORK_TYPE_DONE消息,

然后调用getPhoneFromRequest获取实际的phone对象,当然哪个对象都继承于PhoneBase,

最后的setPreferredNetworkType在PhoneBase中实现,

PhoneBase直接调用RIL的setPreferredNetworkType方法进行设置。

[html] view plain copy
  1. mCi.setPreferredNetworkType(networkType, response);  

最后注意,当RIL收到modem的处理消息时,会向PhoneInterfaceManager发送已经封装的

EVENT_SET_PREFERRED_NETWORK_TYPE_DONE消息。回调处理在此就不论述了。