您的位置:首页 > 移动开发 > Android开发

android 系统数据业务---模式切换分析(上)

2017-07-17 19:55 344 查看

5 setPreferredNetworkType详解

5.1 RIL处理

RIL.java中setPreferredNetworkType方法如下,

@Override
public void setPreferredNetworkType(int networkType , Message response) {
RILRequest rr = RILRequest.obtain(
RILConstants.RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE, response);
rr.mParcel.writeInt(1);
rr.mParcel.writeInt(networkType);
mPreferredNetworkType = networkType;
if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)
+ " : " + networkType);
send(rr);
}


发送的是RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE类型的消息。

 

每一个通过RIL发送的消息都会有对应的返回消息,RIL中的processSolicited方法会对

RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE类型的消息处理如下,

A,首先获取ril库上报的数据,

case RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE: ret =  responseVoid(p); break;

responseVoid方法返回的是null,

B,然后进行回调,

if (rr.mResult != null) {
AsyncResult.forMessage(rr.mResult, ret, null);
rr.mResult.sendToTarget();
}

AsyncResult 回调就一个原则,谁发起谁处理。

回看MobileNetworkSettings的onPreferenceChange方法,

mPhone.setPreferredNetworkType(modemNetworkMode, mHandler
.obtainMessage(MyHandler.MESSAGE_SET_PREFERRED_NETWORK_TYPE));

调用PhoneProxy的setPreferredNetworkType携带的是MESSAGE_SET_PREFERRED_NETWORK_TYPE消息,

因此AsyncResult 回调到MobileNetworkSettings, MobileNetworkSettings中对MESSAGE_SET_PREFERRED_NETWORK_TYPE

消息处理如下,

case MESSAGE_SET_PREFERRED_NETWORK_TYPE:
handleSetPreferredNetworkTypeResponse(msg);
break;

handleSetPreferredNetworkTypeResponse方法如下,

private void handleSetPreferredNetworkTypeResponse(Message msg) {
AsyncResult ar = (AsyncResult) msg.obj;
final int phoneSubId = mPhone.getSubId();
if (ar.exception == null) {
int networkMode = Integer.valueOf(
mButtonPreferredNetworkMode.getValue()).intValue();
android.provider.Settings.Global.putInt(mPhone.getContext().getContentResolver(),
android.provider.Settings.Global.PREFERRED_NETWORK_MODE + phoneSubId,
networkMode );
networkMode = Integer.valueOf(mButtonEnabledNetworks.getValue()).intValue();
android.provider.Settings.Global.putInt(mPhone.getContext().getContentResolver(),
android.provider.Settings.Global.PREFERRED_NETWORK_MODE + phoneSubId,
networkMode );
} else {
mPhone.getPreferredNetworkType(obtainMessage(
MESSAGE_GET_PREFERRED_NETWORK_TYPE));
}
}

A,如果ril库对RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE 消息处理没有出现异常,则再次将网络模式

写入到数据库中保存起来。

B,否则接着调用PhoneProxy的getPreferredNetworkType方法获取当前的网络模式。这个方法的调用流程和

setPreferredNetworkType方法调用流程完全一样,在此就不赘述了。

其实模式切换比打开还要复杂,首先会断开原来的连接,然后重新发起拨号,最后拨号完成。

5.2 RIL_UNSOL_DATA_CALL_LIST_CHANGED

一般情况下,打开数据网络并且设置网络模式之后,就可以正常的拨号上网了.一般的各大国内厂商的手机也都可以上网,

因为基于高通解决方案的reference-ril库比较稳定.但是一些模块厂商的reference-ril库很不稳定,存在或多或少的问题

导致模式切换的时候无法上网。一般情况下,有以下2种情况导致数据业务连接失败:

1, Modem未上报RIL_UNSOL_DATA_CALL_LIST_CHANGED消息,或者上报包含错误码或者链接中断;

2, 数据网络模式切换时,查询 RIL_REQUEST_DATA_REGISTRATION_STATE消息出错;

一般地,在模式切换时,中间会断开并且重新连接一次,而负责重新连接的就是根据modem上报的

RIL_UNSOL_DATA_CALL_LIST_CHANGED消息,RIL.java对的processUnsolicited方法该消息的处理如下,

首先获取并解析底层ril上传的数据,

case RIL_UNSOL_DATA_CALL_LIST_CHANGED: ret = responseDataCallList(p);break;

responseDataCallList方法如下,

private Object
responseDataCallList(Parcel p) {
ArrayList<DataCallResponse> response;
int ver = p.readInt();
int num = p.readInt();//读取socket数据
riljLog("responseDataCallList ver=" + ver + " num=" + num);
response = new ArrayList<DataCallResponse>(num);
for (int i = 0; i < num; i++) {
response.add(getDataCallResponse(p, ver));//解析
}
return response;
}

解析完数据之后,将数据发送出去,进行回调.

case RIL_UNSOL_DATA_CALL_LIST_CHANGED:
if (RILJ_LOGD) unsljLogRet(response, ret);
mDataNetworkStateRegistrants.notifyRegistrants(new AsyncResult(null, ret, null));
break;

RIL.java中的消息都是谁注册谁处理, mDataNetworkStateRegistrants是谁注册的呢?

RIL的父类BaseCommands中, registerForDataNetworkStateChanged方法如下,

@Override
public void registerForDataNetworkStateChanged(Handler h, int what, Object obj) {
Registrant r = new Registrant (h, what, obj);
mDataNetworkStateRegistrants.add(r);
}

DcController的内部类DccDefaultState调用registerForDataNetworkStateChanged方法进行注册的,

DccDefaultState是一个状态机,刚开始进入该状态时就会注册,

public void enter() {
mPhone.mCi.registerForRilConnected(getHandler(),
DataConnection.EVENT_RIL_CONNECTED, null);
mPhone.mCi.registerForDataNetworkStateChanged(getHandler(),
DataConnection.EVENT_DATA_STATE_CHANGED, null);
if (Build.IS_DEBUGGABLE) {
mDcTesterDeactivateAll =
new DcTesterDeactivateAll(mPhone, DcController.this, getHandler());
}
}

注册时handler类型是EVENT_DATA_STATE_CHANGED,因此, mDataNetworkStateRegistrants.notifyRegistrants(newAsyncResult(null, ret, null)) 

这句回调的是DccDefaultState的processMessage方法,有关EVENT_DATA_STATE_CHANGED消息处理的代码如下,

case DataConnection.EVENT_DATA_STATE_CHANGED:
ar = (AsyncResult)msg.obj;
if (ar.exception == null) {
onDataStateChanged((ArrayList<DataCallResponse>)ar.result);
} else {
log("DccDefaultState: EVENT_DATA_STATE_CHANGED:" +
" exception; likely radio not available, ignore");
}
break;

在onDataStateChanged方法中,首先读取上报的数据,然后根据状态做不同的处理.

一般数据网络模式切换时候出现问题大部分都是因为RIL_UNSOL_DATA_CALL_LIST_CHANGED消息,具体的问题可以

分析onDataStateChanged方法,该方法会打出大量的log。

RIL上报RIL_UNSOL_DATA_CALL_LIST_CHANGED消息时,一般会有2种结果,

1,网络从连接的状态转到断开状态;

2,网络从断开状态转到连接状态。

5.2.1 转到断开状态

如果当前状态是连接状态,在onDataStateChanged中关键代码如下,

for (DataConnection dc : dcsToRetry) {
dc.sendMessage(DataConnection.EVENT_LOST_CONNECTION, dc.mTag);
}

然后DataConnection中的DcActiveState状态的processMessage方法就会处理EVENT_LOST_CONNECTION消息,

case EVENT_LOST_CONNECTION: {
•••
if (mRetryManager.isRetryNeeded()) {
•••
mDcRetryAlarmController.startRetryAlarm(EVENT_RETRY_CONNECTION, mTag,
delayMillis);
transitionTo(mRetryingState);
}
•••

跳转到DcRetryingState状态,就像在第三章中论述的那样,无论DcActiveState跳到哪种状态,最后都会调用exit方法进而

调用NetworkAgent的sendNetworkInfo方法更新网络状态。

如果是正常断开的话,DcRetryingState状态会立即转为DcInactiveState状态,

DcRetryingState的enter方法中对应的代码如下,

mInactiveState.setEnterNotificationParams(DcFailCause.LOST_CONNECTION);
transitionTo(mInactiveState);

5.2.2 转到连接状态

从DcInactiveState状态一直转换到DcActiveState状态的过程详见第2.3小节。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息