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小节。 |