当前位置:   article > 正文

基于Android11的拨号流程分析_android 框架 拨打电话流程

android 框架 拨打电话流程

目录

1、概述

2、流程图

3、类图

4、拨号流程分析

4.1 ServiceStateTracker分析

4.2 DcTracker分析

4.3 DataConnection分析

4.3.1 状态机机制

4.3.2 DataConnection状态树

4.3.3 bringUp流程分析

4.4 DataServiceManager分析

4.5 DataService分析

5、重点函数分析

5.1 pollStateDone调用分析

5.2 setupDataOnAllConnectableApns调用分析

6、总结


1、概述

拨号分析也就是数据业务如何建立起来,本文档用于分析及总结拨号的流程,用于后面快速定位RIL拨号这块出现的问题。

2、流程图

从流程图来看,调用很清楚,但重点在DataService里并没有去真正实现setupDataCall功能,而是通过其他provider类继承他实现setupDataCall功能。通过继承特性,我们可以看出,这个设计意思是后面计划有可能多个provider,但实际代码搜了下,目前只有CellularDataServiceProvider,可能框架先做好,后面想添加时,直接实现就行。从这里看出,大老设计的代码就是优秀,普通人不会想那么长远。这也体现了代码的艺术。

3、类图

从类图层次来看,拨号可分为4层,自上到下分别为Data应用、Data接口、Data服务、RILJ。

 

  • Data应用:内容主要是确认是否满足拨号及拨号过程处理;
  • Data接口:封闭Data服务,对外提供接口;
  • Data服务:提供拨号的接口;
  • RILJ:向RILD发起拨号。

Data应用:重点由DcTracker、ServiceStateTracker和DataConnecion 3个类组成。ServiceStateTracker用于处理当前的网络状态,如data voice 信号等。DcTracker用于拨号的逻辑处理流程,如是否打开数据业务,APN组装等。DataConnection是拨号的一个状态机。DataServiceManager用于提供DataService的接口。

Data接口:封装服务对外提供的接口,按设计模式的思路是外面不需要关心具体的接口如何实现,只管调用。

Data服务:此处可以再细分为提供者和服务。提供者由CellularDataServiceProvider和CellularDataService组成,从类图可以看出,都是继承了服务里的相关类;服务重点由DataService组成。DataService用于提供拨号的相关服务,DataServiceProvider和IDataServiceWrapper通过向DataServiceHandler发Message消息进行相关逻辑处理,IDataServiceWrapper是实现AIDL接口,也就是对外提供的服务接口。

RILJ用于向RILD处下RIL消息,本文档不重点介绍此处功能。

4、拨号流程分析

完整拨号的时序图如下。

 

4.1 ServiceStateTracker分析

在RILJ 的4个网络状态operator、voice、data、selection mode查询时,会触发对应的handle消息然后调用handlePollStateResult,见如下代码:

  1. case EVENT_POLL_STATE_CS_CELLULAR_REGISTRATION:
  2. case EVENT_POLL_STATE_PS_CELLULAR_REGISTRATION:
  3. case EVENT_POLL_STATE_PS_IWLAN_REGISTRATION:
  4. case EVENT_POLL_STATE_OPERATOR:
  5.     ar = (AsyncResult) msg.obj;
  6.     handlePollStateResult(msg.what, ar);
  7. break;
  8. case EVENT_POLL_STATE_NETWORK_SELECTION_MODE:
  9.     if (DBG) log("EVENT_POLL_STATE_NETWORK_SELECTION_MODE");
  10.     ar = (AsyncResult) msg.obj;
  11.     if (mPhone.isPhoneTypeGsm()) {
  12.         handlePollStateResult(msg.what, ar);
  13.     } else {
  14.         if (ar.exception == null && ar.result != null) {
  15.             ints = (int[])ar.result;
  16.         if (ints[0] == 1) { // Manual selection.
  17.             mPhone.setNetworkSelectionModeAutomatic(null);
  18.         }
  19.     } else {
  20.         log("Unable to getNetworkSelectionMode");
  21.     }
  22.     }
  23. break;

而handlePollStateResult的作用是更新mNewSS的状态,mNewSS是ServiceState的对象,用于获取本次网络的最新状态。在4个网络状态完成查询后,会调用pollStateDone函数,同时mNewSS也完成了更新。

pollStateDone函数作用是根据oldSS和mNewSS的变化来修改一些状态,然后根据这些状态发出消息做出相应的动作。比如针对拨号流程需要确认hasDataAttached是否附着上,附着的判断条件代码如下:

  1. boolean changed = (oldNrs == null || !oldNrs.isInService() || hasAirplaneModeOnChanged)&& (newNrs != null && newNrs.isInService());
  2. hasDataAttached.put(transport, changed);

changed条件为ture的情况是(oldNrs为空或者oldNrs未注册上或者飞行模式变化)并且(newNrs不为空并且newNrs已注册)。oldNrs和newNrs分别是通过如下代码获取。

  1. NetworkRegistrationInfo oldNrs = mSS.getNetworkRegistrationInfo(
  2. NetworkRegistrationInfo.DOMAIN_PS, transport);
  3. NetworkRegistrationInfo newNrs = mNewSS.getNetworkRegistrationInfo(
  4. NetworkRegistrationInfo.DOMAIN_PS, transport);

在状态完成修改后,mSS和mNewSS的变化如下图,mNewSS的最新状态给mSS,而mNewSS自行clean掉。后面应用或系统获取的网络状态都是从mSS获取。

  1. ServiceState tss = mSS;
  2. mSS = mNewSS;
  3. mNewSS = tss;
  4. // clean slate for next time
  5. mNewSS.setStateOutOfService();

hasDataDetached.put(transport, changed);这语句里的transport通过跟踪代码可以有两个值,一个是wwan另一个是wlan,此处是wwan无线广域网。如果changed为true的话,那么下面这段判断代码会被执行。

  1. if (hasDataAttached.get(transport)) {
  2.     shouldLogAttachedChange = true;
  3.     if (mAttachedRegistrants.get(transport) != null) {
  4.         mAttachedRegistrants.get(transport).notifyRegistrants();
  5.     }
  6. }

mAttachedRegistrants发出通知,通过mAttachedRegistrants搜关键字,最终是在DcTracker的registerServiceStateTrackerEvents函数进行的注册,这里其实用到了观察者设计模式。

  1. public void registerServiceStateTrackerEvents() {
  2. mPhone.getServiceStateTracker().registerForDataConnectionAttached(mTransportType, this,
  3. DctConstants.EVENT_DATA_CONNECTION_ATTACHED, null);
  4. mPhone.getServiceStateTracker().registerForDataConnectionDetached(mTransportType, this,
  5. DctConstants.EVENT_DATA_CONNECTION_DETACHED, null);
  6. mPhone.getServiceStateTracker().registerForDataRoamingOn(this,
  7. DctConstants.EVENT_ROAMING_ON, null);
  8. mPhone.getServiceStateTracker().registerForDataRoamingOff(this,
  9. DctConstants.EVENT_ROAMING_OFF, null, true);
  10. mPhone.getServiceStateTracker().registerForPsRestrictedEnabled(this,
  11. DctConstants.EVENT_PS_RESTRICT_ENABLED, null);
  12. mPhone.getServiceStateTracker().registerForPsRestrictedDisabled(this,
  13. DctConstants.EVENT_PS_RESTRICT_DISABLED, null);
  14. mPhone.getServiceStateTracker().registerForDataRegStateOrRatChanged(mTransportType, this,
  15. DctConstants.EVENT_DATA_RAT_CHANGED, null);
  16. }

4.2 DcTracker分析

至此,我们开始进入到了DcTracker类分析。通过代码跟踪消息EVENT_DATA_CONNECTION_ATTACHED发出后,依次调用onDataConnectionAttached-->setupDataOnAllConnectableApns-->setupDataOnConnectableApn-->trySetupData。

通过分析trySetupData代码,做了两个动作,一个是确认是否允许拨号;另一个是准备APN。

1)允许拨号检测:函数为isDataAllowed,里面有步骤介绍。因代码量有点多,就不帖出来。

  1. DataConnectionReasons dataConnectionReasons = new DataConnectionReasons();
  2. boolean isDataAllowed = isDataAllowed(apnContext, requestType, dataConnectionReasons);
  3. String logStr = "trySetupData for APN type " + apnContext.getApnType() + ", reason: "
  4. + apnContext.getReason() + ", requestType=" + requestTypeToString(requestType)
  5. + ". " + dataConnectionReasons.toString();

步骤1:获取所有环境条件,比如是否打开数据业务,Data是否Attach,radio是否关了等;

步骤2:如果是紧急的APN,允许拨号;

步骤3:根据状态,把不允许拨号的原因添加到reasons来;

步骤4:确定在某些特殊条件下是否允许数据。此步骤如果成立,会把步骤3的数据清空。

步骤5:返回reaseons.allowed(),此函数的作用是步骤3添加的条数是否为0,如果为0,则允许。

此处的细节也很多,也没有去细看,只看了个大概框架,后面如果有问题没有拨号的话,可以看看这里是否不允许拨号引起。

2)APN准备:buildWaitingApns使用用户设置的preferred APN构建一个可用于数据连接的备选APN列表,即waitingApns列表(当有preferred APN,该列表就只有一个)。若用户没有设置preferred APN,则将所有类型匹配的APN添加到waitingApns列表(如default类型)。当trySetupData函数检查有waitingApns列表中有可用的APN时,就会去尝试建立连接。

完成如上步骤后调用setupData,再进入到DataConnection调用bringUp。

  1. boolean retValue = setupData(apnContext, radioTech, requestType);
  2. if (DBG) log("trySetupData: X retValue=" + retValue);
  3. return retValue;

4.3 DataConnection分析

DataConnection是继承StateMachine,是个状态机类。

4.3.1 状态机机制

如果对状态机的处理机制不理解的话,完全是不知道消息怎么处理或在哪处理。这里根据个人从网上学习总结的状态机原理如下。

接口说明:

enter:进入节点执行此函数

exit:退出节点执行此函数

processMessage:消息处理函数

消息处理机制:

1)先执行子节点再执行父节点;

2)子节点的消息如果已找到,就不去调用父节点;

3)子节点的消息未找到,则到父节点上找,直到找到。

切换(transitionTo)处理机制:

状态A到状态B切换时的调用栈就是从状态A回到两者的公共父节点,再走到状态B的最短路线。这里的回就是执行exit函数,走就是enter函数。

示例:

如下面的状态树

假设S4为初始状态,如果要从S4切到S7,状态树是如何处理。其切换机制是这样:S4.exit->S1.exit->S2.enter->S7.enter。

注意:父节点不需要退出再进入。

4.3.2 DataConnection状态树

而关于本类DataConnection的状态树代码如下:

  1. addState(mDefaultState);
  2.     addState(mInactiveState, mDefaultState);
  3.     addState(mActivatingState, mDefaultState);
  4.     addState(mActiveState, mDefaultState);
  5.     addState(mDisconnectingState, mDefaultState);
  6.     addState(mDisconnectingErrorCreatingConnection, mDefaultState);
  7. setInitialState(mInactiveState);

对应的状态树如下:

开始状态为mInactiveState。

4.3.3 bringUp流程分析

此函数就简单的发出EVENT_CONNECT消息,而如果在此类搜EVENT_CONNECT关键字,有很多地方处理,所以如果不理解状态树时,完全不知道走的是哪个地方。通过上面对状态树的了解,当前的开始状态是mInactiveState,所以我们到mInactiveState这个类看看看有没有对EVENT_CONNECT的处理,通过代码发现,果然有,代码如下:

  1. public boolean processMessage(Message msg) {
  2. switch (msg.what) {
  3. case EVENT_RESET:
  4. case EVENT_REEVALUATE_RESTRICTED_STATE:
  5. if (DBG) {
  6. log("DcInactiveState: msg.what=" + getWhatToString(msg.what)
  7. + ", ignore we're already done");
  8. }
  9. return HANDLED;
  10. case EVENT_CONNECT:
  11. if (DBG) log("DcInactiveState: mag.what=EVENT_CONNECT");
  12. ConnectionParams cp = (ConnectionParams) msg.obj;
  13. if (!initConnection(cp)) {
  14. log("DcInactiveState: msg.what=EVENT_CONNECT initConnection failed");
  15. notifyConnectCompleted(cp, DataFailCause.UNACCEPTABLE_NETWORK_PARAMETER,
  16. false);
  17. transitionTo(mInactiveState);
  18. return HANDLED;
  19. }
  20. int cause = connect(cp);
  21. if (cause != DataFailCause.NONE) {
  22. log("DcInactiveState: msg.what=EVENT_CONNECT connect failed");
  23. notifyConnectCompleted(cp, cause, false);
  24. transitionTo(mInactiveState);
  25. return HANDLED;
  26. }
  27. if (mSubId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
  28. mSubId = cp.mSubId;
  29. }
  30. transitionTo(mActivatingState);
  31. return HANDLED;
  32. case EVENT_DISCONNECT:
  33. if (DBG) log("DcInactiveState: msg.what=EVENT_DISCONNECT");
  34. notifyDisconnectCompleted((DisconnectParams)msg.obj, false);
  35. return HANDLED;
  36. case EVENT_DISCONNECT_ALL:
  37. if (DBG) log("DcInactiveState: msg.what=EVENT_DISCONNECT_ALL");
  38. notifyDisconnectCompleted((DisconnectParams)msg.obj, false);
  39. return HANDLED;
  40. default:
  41. if (VDBG) {
  42. log("DcInactiveState not handled msg.what=" + getWhatToString(msg.what));
  43. }
  44. return NOT_HANDLED;
  45. }
  46. }

从代码可以看出,如果connect失败了,状态会继续切到mInactiveState,而如果connect成功,状态会切到mActivatingState。

connect函数最终调用如下代码处理拨号流程。

  1. mDataServiceManager.setupDataCall(
  2.     ServiceState.rilRadioTechnologyToAccessNetworkType(cp.mRilRat),
  3.     dp,
  4.     isModemRoaming,
  5.     allowRoaming,
  6.     reason,
  7.     linkProperties,
  8.     msg);
  9. TelephonyMetrics.getInstance().writeSetupDataCall(mPhone.getPhoneId(), cp.mRilRat,dp.getProfileId(), dp.getApn(), dp.getProtocolType());
  10. return DataFailCause.NONE;

4.4 DataServiceManager分析

上面介绍的类都是关于拨号的逻辑处理,到了这一步跟拨号逻辑没关,而是跟设计模式有关了。Android出现Manager类,几乎都是接口的提供,相当代理。拨号调用此类的setupDataCall相关代码如下:

  1. public void setupDataCall(int accessNetworkType, DataProfile dataProfile, boolean isRoaming,
  2. boolean allowRoaming, int reason, LinkProperties linkProperties,
  3. Message onCompleteMessage) {
  4. if (DBG) log("setupDataCall");
  5. if (!mBound) {
  6. loge("Data service not bound.");
  7. sendCompleteMessage(onCompleteMessage, DataServiceCallback.RESULT_ERROR_ILLEGAL_STATE);
  8. return;
  9. }
  10. CellularDataServiceCallback callback = new CellularDataServiceCallback("setupDataCall");
  11. if (onCompleteMessage != null) {
  12. mMessageMap.put(callback.asBinder(), onCompleteMessage);
  13. }
  14. try {
  15. sendMessageDelayed(obtainMessage(EVENT_WATCHDOG_TIMEOUT, callback),
  16. REQUEST_UNRESPONDED_TIMEOUT);
  17. mIDataService.setupDataCall(mPhone.getPhoneId(), accessNetworkType, dataProfile,
  18. isRoaming, allowRoaming, reason, linkProperties, callback);
  19. } catch (RemoteException e) {
  20. loge("Cannot invoke setupDataCall on data service.");
  21. mMessageMap.remove(callback.asBinder());
  22. sendCompleteMessage(onCompleteMessage, DataServiceCallback.RESULT_ERROR_ILLEGAL_STATE);
  23. }
  24. }

然后通过对象mIDataService调用setupDataCall。而mIDataService是怎么来有什么用,这里简单分析下。首先要了解下类的关系。

CellularDataService是继承DataService,DataService继承Service,可知是个服务。DataService又有一个IDataServiceWrapper,IDataServiceWrapper这个类是继承IDataService.Stub,可以看出是个AIDL接口,DataService后面对外接口都是由此类提供。

CellularDataService是在packages\services\Telephony\Android.mk注册,代码如下:

CellularDataService的启动是通过在DataServiceManager类的函数bindDataService里调用bindService启动。

  1. try {
  2.     mServiceConnection = new CellularDataServiceConnection();
  3.     if (!mPhone.getContext().bindService(
  4.     intent, mServiceConnection, Context.BIND_AUTO_CREATE)) {
  5.     loge("Cannot bind to the data service.");
  6.     return;
  7. }
  8.     mTargetBindingPackageName = packageName;
  9. } catch (Exception e) {
  10.     loge("Cannot bind to the data service. Exception: " + e);
  11. }

CellularDataService成功启动后,通过回调mServiceConnection. onServiceConnected函数,这里面就可以获取到IDataServiceWrapper的对象,上面已说,此对象是DataService对外提供的接口。代码如下:

  1. @Override
  2. public void onServiceConnected(ComponentName name, IBinder service) {
  3. if (DBG) log("onServiceConnected");
  4.     mIDataService = IDataService.Stub.asInterface(service);
  5.     mDeathRecipient = new DataServiceManagerDeathRecipient();
  6.     mBound = true;
  7. try {
  8.     service.linkToDeath(mDeathRecipient, 0);
  9.     mIDataService.createDataServiceProvider(mPhone.getPhoneId());
  10.     mIDataService.registerForDataCallListChanged(mPhone.getPhoneId(),
  11.     new CellularDataServiceCallback("dataCallListChanged"));
  12. } catch (RemoteException e) {
  13.     mDeathRecipient.binderDied();
  14.     loge("Remote exception. " + e);
  15.     return;
  16. }
  17. removeMessages(EVENT_WATCHDOG_TIMEOUT);
  18. mServiceBindingChangedRegistrants.notifyResult(true);
  19. }

4.5 DataService分析

继续回头分析mIDataService.setupDataCall,上面已提到,mIDataService对象就由IDataServiceWrapper提供。setupDataCall发出DATA_SERVICE_REQUEST_SETUP_DATA_CALL消息,这个消息的处理代码如下:

  1. case DATA_SERVICE_REQUEST_SETUP_DATA_CALL:
  2. if (serviceProvider == null) break;
  3. SetupDataCallRequest setupDataCallRequest = (SetupDataCallRequest) message.obj;
  4. serviceProvider.setupDataCall(setupDataCallRequest.accessNetworkType,
  5. setupDataCallRequest.dataProfile, setupDataCallRequest.isRoaming,
  6. setupDataCallRequest.allowRoaming, setupDataCallRequest.reason,
  7. setupDataCallRequest.linkProperties,
  8. (setupDataCallRequest.callback != null)
  9. ? new DataServiceCallback(setupDataCallRequest.callback)
  10. : null);
  11. break;

接下来是通过serviceProvider调用setupDataCall,而serviceProvider从哪来?

从DataServiceManager介绍,当mServiceConnection.onServiceConnected回调后,会通过调用mIDataService.createDataServiceProvider函数。

  1. private final class CellularDataServiceConnection implements ServiceConnection {
  2. @Override
  3. public void onServiceConnected(ComponentName name, IBinder service) {
  4. if (DBG) log("onServiceConnected");
  5. mIDataService = IDataService.Stub.asInterface(service);
  6. mDeathRecipient = new DataServiceManagerDeathRecipient();
  7. mBound = true;
  8. try {
  9. service.linkToDeath(mDeathRecipient, 0);
  10. mIDataService.createDataServiceProvider(mPhone.getPhoneId());
  11. mIDataService.registerForDataCallListChanged(mPhone.getPhoneId(),
  12. new CellularDataServiceCallback("dataCallListChanged"));
  13. } catch (RemoteException e) {
  14. mDeathRecipient.binderDied();
  15. loge("Remote exception. " + e);
  16. return;
  17. }
  18. removeMessages(EVENT_WATCHDOG_TIMEOUT);
  19. mServiceBindingChangedRegistrants.notifyResult(true);
  20. }

 createDataServiceProvider函数发出消息DATA_SERVICE_CREATE_DATA_SERVICE_PROVIDER,处理代码如下:

  1. case DATA_SERVICE_CREATE_DATA_SERVICE_PROVIDER:
  2. serviceProvider = onCreateDataServiceProvider(message.arg1);
  3. if (serviceProvider != null) {
  4. mServiceMap.put(slotIndex, serviceProvider);
  5. }
  6. break;

最后调用onCreateDataServiceProvider完成serviceProvider创建,但onCreateDataServiceProvider是DataService的抽像函数,真正实现的类是在CellularDataService,代码如下:

  1. public DataServiceProvider onCreateDataServiceProvider(int slotIndex) {
  2. log("Cellular data service created for slot " + slotIndex);
  3. if (!SubscriptionManager.isValidSlotIndex(slotIndex)) {
  4. loge("Tried to cellular data service with invalid slotId " + slotIndex);
  5. return null;
  6. }
  7. return new CellularDataServiceProvider(slotIndex);
  8. }

也就是serviceProvider是通过CellularDataServiceProvider创建,CellularDataServiceProvider的setupDataCall函数内容如下:

  1. @Override
  2. public void setupDataCall(int accessNetworkType, DataProfile dataProfile, boolean isRoaming,
  3. boolean allowRoaming, int reason, LinkProperties linkProperties,
  4. DataServiceCallback callback) {
  5. if (DBG) log("setupDataCall " + getSlotIndex());
  6. Message message = null;
  7. // Only obtain the message when the caller wants a callback. If the caller doesn't care
  8. // the request completed or results, then no need to pass the message down.
  9. if (callback != null) {
  10. message = Message.obtain(mHandler, SETUP_DATA_CALL_COMPLETE);
  11. mCallbackMap.put(message, callback);
  12. }
  13. mPhone.mCi.setupDataCall(accessNetworkType, dataProfile, isRoaming, allowRoaming,
  14. reason, linkProperties, message);
  15. }

通过代码可以看出,最后调用了RILJ的setupDataCall。

相关时序如图下:

5、重点函数分析

本章节主要再细讲下pollStateDone和setupDataOnAllConnectableApns两函数,对这两函数了解了,相当于对整个过程起到中流砥柱作用。

5.1 pollStateDone调用分析

通过代码搜索看到,pollStateDone除了handlePollStateResult函数调用外,还有pollStateInternal函数调用,pollStateInternal具体流程如下。

  • Radio不可用时调用pollStateDone。
  • Radio off的状态:根据传入的参数modemTriggered(中文意为调制解调器触发),来区分是不是modem来触发调用。如果非modem触发,调用pollStateDone。
  • 主动查询operator、voice、data状态,完成查询后,又回到调用handlePollStateResult流程调用pollStateDone。
  1. private void pollStateInternal(boolean modemTriggered) {
  2. mPollingContext = new int[1];
  3. mPollingContext[0] = 0;
  4. log("pollState: modemTriggered=" + modemTriggered);
  5. switch (mCi.getRadioState()) {
  6. case TelephonyManager.RADIO_POWER_UNAVAILABLE:
  7. mNewSS.setStateOutOfService();
  8. setSignalStrengthDefaultValues();
  9. mLastNitzData = null;
  10. mNitzState.handleNetworkUnavailable();
  11. pollStateDone();
  12. break;
  13. case TelephonyManager.RADIO_POWER_OFF:
  14. mNewSS.setStateOff();
  15. setSignalStrengthDefaultValues();
  16. mLastNitzData = null;
  17. mNitzState.handleNetworkUnavailable();
  18. // don't poll when device is shutting down or the poll was not modemTrigged
  19. // (they sent us new radio data) and current network is not IWLAN
  20. if (mDeviceShuttingDown ||
  21. (!modemTriggered && ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN
  22. != mSS.getRilDataRadioTechnology())) {
  23. pollStateDone();
  24. break;
  25. }
  26. default:
  27. // Issue all poll-related commands at once then count down the responses, which
  28. // are allowed to arrive out-of-order
  29. mPollingContext[0]++;
  30. mCi.getOperator(obtainMessage(EVENT_POLL_STATE_OPERATOR, mPollingContext));
  31. mPollingContext[0]++;
  32. mRegStateManagers.get(AccessNetworkConstants.TRANSPORT_TYPE_WWAN)
  33. .requestNetworkRegistrationInfo(NetworkRegistrationInfo.DOMAIN_PS,
  34. obtainMessage(EVENT_POLL_STATE_PS_CELLULAR_REGISTRATION,
  35. mPollingContext));
  36. mPollingContext[0]++;
  37. mRegStateManagers.get(AccessNetworkConstants.TRANSPORT_TYPE_WWAN)
  38. .requestNetworkRegistrationInfo(NetworkRegistrationInfo.DOMAIN_CS,
  39. obtainMessage(EVENT_POLL_STATE_CS_CELLULAR_REGISTRATION, mPollingContext));
  40. if (mRegStateManagers.get(AccessNetworkConstants.TRANSPORT_TYPE_WLAN) != null) {
  41. mPollingContext[0]++;
  42. mRegStateManagers.get(AccessNetworkConstants.TRANSPORT_TYPE_WLAN)
  43. .requestNetworkRegistrationInfo(NetworkRegistrationInfo.DOMAIN_PS,
  44. obtainMessage(EVENT_POLL_STATE_PS_IWLAN_REGISTRATION,
  45. mPollingContext));
  46. }
  47. if (mPhone.isPhoneTypeGsm()) {
  48. mPollingContext[0]++;
  49. mCi.getNetworkSelectionMode(obtainMessage(
  50. EVENT_POLL_STATE_NETWORK_SELECTION_MODE, mPollingContext));
  51. }
  52. break;
  53. }

5.2 setupDataOnAllConnectableApns调用分析

在第三章有略带过讲到了拨号流程过程中会调用setupDataOnAllConnectableApns此函数。通过在代码搜索,调用的地方有:

onDataConnectionAttached:Data附着上

onApnChanged:APN有修改

onCarrierConfigChanged:SIM完成加载

onSimStateUpdated:SIM卡状态更新,如插入,拔出,ready,完成加载这类状态

onDataRoamingOnOrSettingsChanged:打开漫游

onVoiceCallEnded:语音通话结束

DctConstants.EVENT_DATA_RAT_CHANGED:radio technology 有变化

onDataEnabledChanged:数据业务开关

针对出现不拨号的问题都可以根据这些函数入手。从这些函数调用可以看出,拨号接口函数应该是setupDataOnAllConnectableApns,而不是trySetupDataCall。

函数代码:   

  1. protected void setupDataOnAllConnectableApns(String reason, RetryFailures retryFailures) {
  2. if (VDBG) log("setupDataOnAllConnectableApns: " + reason);
  3. if (DBG && !VDBG) {
  4. StringBuilder sb = new StringBuilder(120);
  5. for (ApnContext apnContext : mPrioritySortedApnContexts) {
  6. sb.append(apnContext.getApnType());
  7. sb.append(":[state=");
  8. sb.append(apnContext.getState());
  9. sb.append(",enabled=");
  10. sb.append(apnContext.isEnabled());
  11. sb.append("] ");
  12. }
  13. log("setupDataOnAllConnectableApns: " + reason + " " + sb);
  14. }
  15. for (ApnContext apnContext : mPrioritySortedApnContexts) {
  16. setupDataOnConnectableApn(apnContext, reason, retryFailures);
  17. }
  18. }

 此函数通过过滤mPrioritySortedApnContexts的ApnContext,确认哪个ApnContext可连接然后进行拨号,而确认ApnContext可连接的函数是在setupDataOnConnectableApn

  1. protected void setupDataOnConnectableApn(ApnContext apnContext, String reason,
  2. RetryFailures retryFailures) {
  3. if (VDBG) log("setupDataOnAllConnectableApns: apnContext " + apnContext);
  4. if (apnContext.getState() == DctConstants.State.FAILED
  5. || apnContext.getState() == DctConstants.State.RETRYING) {
  6. if (retryFailures == RetryFailures.ALWAYS) {
  7. apnContext.releaseDataConnection(reason);
  8. } else if (!apnContext.isConcurrentVoiceAndDataAllowed()
  9. && mPhone.getServiceStateTracker().isConcurrentVoiceAndDataAllowed()) {
  10. // RetryFailures.ONLY_ON_CHANGE - check if voice concurrency has changed
  11. apnContext.releaseDataConnection(reason);
  12. }
  13. }
  14. if (apnContext.isConnectable()) {
  15. log("isConnectable() call trySetupData");
  16. apnContext.setReason(reason);
  17. trySetupData(apnContext, REQUEST_TYPE_NORMAL);
  18. }
  19. }

这里不再详细讲ApnContext如何被置为可连接,因为这涉及到另外一个功能:网络评分机制,后面再总结。而mPrioritySortedApnContexts的值从哪来有什么用,这里简单说一下。

initApnContexts-->initApnContexts (PersistableBundle carrierConfig)

 从上图可以看到,最终是由initApnContexts函数的参数carrierConfig决定。carrierConfig的值是由下图获取。

通过代码跟踪(这里很不好跟,结合网上资料才知道),最终是解析packages\apps\CarrierConfig\assets里面的xml获得。解析函数是:packages\apps\CarrierConfig\src\com\android\carrierconfig\DefaultCarrierConfigService.java类里的loadConfig。但通过log发现,里面并没有相关国内运营商的配置。也就是carrierConfig是没有任何值的。但log里面又显示有值:

一开始还怀疑是不是跟错了,流程又看了几次还是没找到原因。最终通过看到一个不起眼的函数找到了答案。重新回头看看initApnContexts (PersistableBundle carrierConfig)函数 

 

这里通过ApnConfigTypeRepository 创建了types对象,进入到ApnConfigTypeRepository类里面的创建过程调用了下面函数

private void setup(PersistableBundle carrierConfig) {
    addApns(getCarrierApnTypeMap(CarrierConfigManager.getDefaultConfig()));
    addApns(getCarrierApnTypeMap(carrierConfig));
}

CarrierConfigManager.getDefaultConfig()代码如下,关键参数是sDefaults

public static PersistableBundle getDefaultConfig() {

    return new PersistableBundle(sDefaults);

}

sDefaults的初始化是在CarrierConfigManager类里面,关键代码是

 sDefaults.putStringArray(KEY_APN_PRIORITY_STRING_ARRAY, new String[] {
                "default:0", "mms:2", "supl:2", "dun:2", "hipri:3", "fota:2",
                "ims:2", "cbs:2", "ia:2", "emergency:2", "mcx:3", "xcap:3"
        });

至此,终于找到了初始化的地方,跟LOG打印一致。而mPrioritySortedApnContexts的作用目前来看是通过Apn类型创建ApnContexts,用来明确此运营商支持哪些APN类型。

6、总结

    本文档其实细节的内容不少,有些只是带过讲而已。但由于篇幅问题,细节的问题可以留到后面具体问题具体展开分析。因为有了整体流程,细节就不是问题了。比如根据之前调试RIL库时遇到不拨号的问题有ApnContext未enable,APN未添加,Data未附着,数据业务未打开等都是可以从本文章展开分析。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/你好赵伟/article/detail/988270
推荐阅读
相关标签
  

闽ICP备14008679号