在前面,我们分析过DcTracker的初始化的时候,我们有看过,在DcTracker的构造方法中,调用有如下这个方法
private void registerForAllEvents() {
mPhone.mCi.registerForAvailable(this, DctConstants.EVENT_RADIO_AVAILABLE, null);
mPhone.mCi.registerForOffOrNotAvailable(this,
DctConstants.EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null);
mPhone.mCi.registerForDataNetworkStateChanged(this,
DctConstants.EVENT_DATA_STATE_CHANGED, null);
// Note, this is fragile - the Phone is now presenting a merged picture
// of PS (volte) & CS and by diving into its internals you're just seeing
// the CS data. This works well for the purposes this is currently used for
// but that may not always be the case. Should probably be redesigned to
// accurately reflect what we're really interested in (registerForCSVoiceCallEnded).
mPhone.getCallTracker().registerForVoiceCallEnded(this,
DctConstants.EVENT_VOICE_CALL_ENDED, null);
mPhone.getCallTracker().registerForVoiceCallStarted(this,
DctConstants.EVENT_VOICE_CALL_STARTED, null);
registerServiceStateTrackerEvents();
// SubscriptionManager.registerForDdsSwitch(this,
// DctConstants.EVENT_CLEAN_UP_ALL_CONNECTIONS, null);
mPhone.mCi.registerForPcoData(this, DctConstants.EVENT_PCO_DATA_RECEIVED, null);
}
其中有调用到registerServiceStateTrackerEvents方法
public void registerServiceStateTrackerEvents() {
// Leo,注册DataConnectionAttached消息
mPhone.getServiceStateTracker().registerForDataConnectionAttached(this,
DctConstants.EVENT_DATA_CONNECTION_ATTACHED, null);
mPhone.getServiceStateTracker().registerForDataConnectionDetached(this,
DctConstants.EVENT_DATA_CONNECTION_DETACHED, null);
mPhone.getServiceStateTracker().registerForDataRoamingOn(this,
DctConstants.EVENT_ROAMING_ON, null);
mPhone.getServiceStateTracker().registerForDataRoamingOff(this,
DctConstants.EVENT_ROAMING_OFF, null);
mPhone.getServiceStateTracker().registerForPsRestrictedEnabled(this,
DctConstants.EVENT_PS_RESTRICT_ENABLED, null);
mPhone.getServiceStateTracker().registerForPsRestrictedDisabled(this,
DctConstants.EVENT_PS_RESTRICT_DISABLED, null);
mPhone.getServiceStateTracker().registerForDataRegStateOrRatChanged(this,
DctConstants.EVENT_DATA_RAT_CHANGED, null);
}
这样,就将当前的DcTracker和ServiceStateTracker绑定到一起了,我们看第一个注册消息EVENT_DATA_CONNECTION_ATTACHED,那么他是怎么激活接收的呢?
这个我么就要分析下ServiceStateTracker了,在SIM卡信息加载读取完成后,ServiceStateTracker会发出一个EVENT_SIM_READY消息,然后在其中进行处理
case EVENT_SIM_READY:
// Reset the mPreviousSubId so we treat a SIM power bounce
// as a first boot. See b/19194287
mOnSubscriptionsChangedListener.mPreviousSubId.set(-1);
pollState();
// Signal strength polling stops when radio is off
queueNextSignalStrengthPoll();
break;
恩,调用了pollState方法
public void pollState() {
pollState(false);
}
public void pollState(boolean modemTriggered) {
mPollingContext = new int[1];
mPollingContext[0] = 0;
switch (mCi.getRadioState()) {
......
default:
// Issue all poll-related commands at once then count down the responses, which
// are allowed to arrive out-of-order
mPollingContext[0]++;
mCi.getOperator(obtainMessage(EVENT_POLL_STATE_OPERATOR, mPollingContext));
mPollingContext[0]++;
mCi.getDataRegistrationState(obtainMessage(EVENT_POLL_STATE_GPRS, mPollingContext));
mPollingContext[0]++;
mCi.getVoiceRegistrationState(obtainMessage(EVENT_POLL_STATE_REGISTRATION,
mPollingContext));
if (mPhone.isPhoneTypeGsm()) {
mPollingContext[0]++;
mCi.getNetworkSelectionMode(obtainMessage(
EVENT_POLL_STATE_NETWORK_SELECTION_MODE, mPollingContext));
}
break;
}
}
可以看到,其中分别调用了RIL类的getOperator,getDataRegistrationState和getVoiceRegistrationState方法,针对于这三个方法,我们着重分析一下getDataRegistrationState方法,注意其传入的参数为Message对象,而且Message对象的what为EVENT_POLL_STATE_GPRS,obj为mPollingContext对象
接下来看下RIL类的getDataRegistrationState方法
public void
getDataRegistrationState (Message result) {
RILRequest rr
= RILRequest.obtain(RIL_REQUEST_DATA_REGISTRATION_STATE, result);
if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
send(rr);
}
恩,从前面几篇文章中,我们知道,这个方法,其实是和底层RIL进行交互,并且发送RIL_REQUEST_DATA_REGISTRATION_STATE消息,并且在RIL类中处理modem层反馈的结果,然后将发送传入的Message消息对象,至于究竟如何传递,后续再分析,因此
case EVENT_POLL_STATE_REGISTRATION:
case EVENT_POLL_STATE_GPRS:
case EVENT_POLL_STATE_OPERATOR:
ar = (AsyncResult) msg.obj;
handlePollStateResult(msg.what, ar);
break;
调用了handlePollStateResult方法,其中参数一为消息what,参数二为modem层反馈上来的数据
protected void handlePollStateResult(int what, AsyncResult ar) {
......
mPollingContext[0]--;
if (mPollingContext[0] == 0) {
if (mPhone.isPhoneTypeGsm()) {
updateRoamingState();
mNewSS.setEmergencyOnly(mEmergencyOnly);
} else {
......
}
pollStateDone();
}
}
设置SIM卡网络的状态信息,并调用pollStateDone方法
private void pollStateDone() {
if (mPhone.isPhoneTypeGsm()) {
pollStateDoneGsm();
} else if (mPhone.isPhoneTypeCdma()) {
pollStateDoneCdma();
} else {
pollStateDoneCdmaLte();
}
}
由于SIM卡为GSM格式
private void pollStateDoneGsm() {
......
boolean hasGprsAttached =
mSS.getDataRegState() != ServiceState.STATE_IN_SERVICE
&& mNewSS.getDataRegState() == ServiceState.STATE_IN_SERVICE;
......
if (hasGprsAttached) {
mAttachedRegistrants.notifyRegistrants();
}
if (hasGprsDetached) {
mDetachedRegistrants.notifyRegistrants();
}
......
}
因此,在此处发送了Data Attached的消息,而由于在DcTracker中,将EVENT_DATA_CONNECTION_ATTACHED消息,加入到mAttachedRegistrants中了,因此,DcTracker会接收到EVENT_DATA_CONNECTION_ATTACHED消息,并处理
case DctConstants.EVENT_DATA_CONNECTION_ATTACHED:
onDataConnectionAttached();
break;
调用onDataConnectionAttached方法
private void onDataConnectionAttached() {
if (DBG) log("onDataConnectionAttached");
// Leo,设置为true
mAttached.set(true);
// Leo,条件不成立
if (getOverallState() == DctConstants.State.CONNECTED) {
if (DBG) log("onDataConnectionAttached: start polling notify attached");
startNetStatPoll();
startDataStallAlarm(DATA_STALL_NOT_SUSPECTED);
notifyDataConnection(Phone.REASON_DATA_ATTACHED);
} else {
// Leo,会直接走else分之,设置其申请DataConnection的建立原因为REASON_DATA_ATTACHED
// update APN availability so that APN can be enabled.
notifyOffApnsOfAvailability(Phone.REASON_DATA_ATTACHED);
}
if (mAutoAttachOnCreationConfig) {
// Leo, 设置为true
mAutoAttachOnCreation.set(true);
}
// Leo,最后调用此方法
setupDataOnConnectableApns(Phone.REASON_DATA_ATTACHED);
}
可以看到,在上面,有几个设置为true的地方,结合前面的DataConnection的初始化,我们知道,这两个参数正式影响到DataConnection建立的条件
最后,调用了setupDataOnConnectableApns方法
private void setupDataOnConnectableApns(String reason) {
setupDataOnConnectableApns(reason, RetryFailures.ALWAYS);
}
private void setupDataOnConnectableApns(String reason, RetryFailures retryFailures) {
......
if (apnContext.isConnectable()) {
log("isConnectable() call trySetupData");
apnContext.setReason(reason);
trySetupData(apnContext, waitingApns);
}
}
apnContext.isConnectable()返回值为true,这个请自行分析
OK,又回到了trySetupData方法中
private boolean trySetupData(ApnContext apnContext, ArrayList waitingApns) {
......
// Allow SETUP_DATA request for E-APN to be completed during emergency call
// and MOBILE DATA On/Off cases as well.
boolean isEmergencyApn = apnContext.getApnType().equals(PhoneConstants.APN_TYPE_EMERGENCY);
final ServiceStateTracker sst = mPhone.getServiceStateTracker();
// set to false if apn type is non-metered or if we have a restricted (priveleged)
// request for the network.
// TODO - may want restricted requests to only apply to carrier-limited data access
// rather than applying to user limited as well.
// Exclude DUN for the purposes of the override until we get finer grained
// intention in NetworkRequests
boolean checkUserDataEnabled =
ApnSetting.isMeteredApnType(apnContext.getApnType(), mPhone.getContext(),
mPhone.getSubId(), mPhone.getServiceState().getDataRoaming()) &&
apnContext.hasNoRestrictedRequests(true /*exclude DUN */);
DataAllowFailReason failureReason = new DataAllowFailReason();
// allow data if currently in roaming service, roaming setting disabled
// and requested apn type is non-metered for roaming.
boolean isDataAllowed = isDataAllowed(failureReason) ||
(failureReason.isFailForSingleReason(DataAllowFailReasonType.ROAMING_DISABLED) &&
!(ApnSetting.isMeteredApnType(apnContext.getApnType(), mPhone.getContext(),
mPhone.getSubId(), mPhone.getServiceState().getDataRoaming())));
if (apnContext.isConnectable() && (isEmergencyApn ||
(isDataAllowed && isDataAllowedForApn(apnContext) &&
mDataEnabledSettings.isDataEnabled(checkUserDataEnabled) && !isEmergency()))) {
if (apnContext.getState() == DctConstants.State.FAILED) {
String str = "trySetupData: make a FAILED ApnContext IDLE so its reusable";
if (DBG) log(str);
apnContext.requestLog(str);
apnContext.setState(DctConstants.State.IDLE);
}
int radioTech = mPhone.getServiceState().getRilDataRadioTechnology();
apnContext.setConcurrentVoiceAndDataAllowed(sst.isConcurrentVoiceAndDataAllowed());
if (apnContext.getState() == DctConstants.State.IDLE) {
if (waitingApns == null) {
waitingApns = buildWaitingApns(apnContext.getApnType(), radioTech);
}
if (waitingApns.isEmpty()) {
notifyNoData(DcFailCause.MISSING_UNKNOWN_APN, apnContext);
notifyOffApnsOfAvailability(apnContext.getReason());
String str = "trySetupData: X No APN found retValue=false";
if (DBG) log(str);
apnContext.requestLog(str);
return false;
} else {
apnContext.setWaitingApns(waitingApns);
if (DBG) {
log ("trySetupData: Create from mAllApnSettings : "
+ apnListToString(mAllApnSettings));
}
}
}
boolean retValue = setupData(apnContext, radioTech);
notifyOffApnsOfAvailability(apnContext.getReason());
if (DBG) log("trySetupData: X retValue=" + retValue);
return retValue;
} else {
......
}
}
由于前面在onDataConnectionAttached方法中,设置了两个值为true,因此此处的isDataAllowed返回值为true,因此,会走如上的代码
最终会调用setupData方法,来建立DataConnection
private boolean setupData(ApnContext apnContext, int radioTech) {
if (DBG) log("setupData: apnContext=" + apnContext);
apnContext.requestLog("setupData");
ApnSetting apnSetting;
DcAsyncChannel dcac = null;
apnSetting = apnContext.getNextApnSetting();
if (apnSetting == null) {
if (DBG) log("setupData: return for no apn found!");
return false;
}
int profileId = apnSetting.profileId;
if (profileId == 0) {
profileId = getApnProfileID(apnContext.getApnType());
}
// On CDMA, if we're explicitly asking for DUN, we need have
// a dun-profiled connection so we can't share an existing one
// On GSM/LTE we can share existing apn connections provided they support
// this type.
if (apnContext.getApnType() != PhoneConstants.APN_TYPE_DUN ||
teardownForDun() == false) {
dcac = checkForCompatibleConnectedApnContext(apnContext);
if (dcac != null) {
// Get the dcacApnSetting for the connection we want to share.
ApnSetting dcacApnSetting = dcac.getApnSettingSync();
if (dcacApnSetting != null) {
// Setting is good, so use it.
apnSetting = dcacApnSetting;
}
}
}
if (dcac == null) {
if (isOnlySingleDcAllowed(radioTech)) {
if (isHigherPriorityApnContextActive(apnContext)) {
if (DBG) {
log("setupData: Higher priority ApnContext active. Ignoring call");
}
return false;
}
// Only lower priority calls left. Disconnect them all in this single PDP case
// so that we can bring up the requested higher priority call (once we receive
// response for deactivate request for the calls we are about to disconnect
if (cleanUpAllConnections(true, Phone.REASON_SINGLE_PDN_ARBITRATION)) {
// If any call actually requested to be disconnected, means we can't
// bring up this connection yet as we need to wait for those data calls
// to be disconnected.
if (DBG) log("setupData: Some calls are disconnecting first. Wait and retry");
return false;
}
// No other calls are active, so proceed
if (DBG) log("setupData: Single pdp. Continue setting up data call.");
}
dcac = findFreeDataConnection();
if (dcac == null) {
dcac = createDataConnection();
}
if (dcac == null) {
if (DBG) log("setupData: No free DataConnection and couldn't create one, WEIRD");
return false;
}
}
final int generation = apnContext.incAndGetConnectionGeneration();
if (DBG) {
log("setupData: dcac=" + dcac + " apnSetting=" + apnSetting + " gen#=" + generation);
}
apnContext.setDataConnectionAc(dcac);
apnContext.setApnSetting(apnSetting);
apnContext.setState(DctConstants.State.CONNECTING);
mPhone.notifyDataConnection(apnContext.getReason(), apnContext.getApnType());
Message msg = obtainMessage();
msg.what = DctConstants.EVENT_DATA_SETUP_COMPLETE;
msg.obj = new Pair(apnContext, generation);
dcac.bringUp(apnContext, profileId, radioTech, msg, generation);
if (DBG) log("setupData: initing!");
return true;
}
分析得出结论,最终通过调用createDataConnection方法,新建DcAsyncChannel对象
private DcAsyncChannel createDataConnection() {
if (DBG) log("createDataConnection E");
int id = mUniqueIdGenerator.getAndIncrement();
DataConnection conn = DataConnection.makeDataConnection(mPhone, id,
this, mDcTesterFailBringUpAll, mDcc);
mDataConnections.put(id, conn);
DcAsyncChannel dcac = new DcAsyncChannel(conn, LOG_TAG);
int status = dcac.fullyConnectSync(mPhone.getContext(), this, conn.getHandler());
if (status == AsyncChannel.STATUS_SUCCESSFUL) {
mDataConnectionAcHashMap.put(dcac.getDataConnectionIdSync(), dcac);
} else {
loge("createDataConnection: Could not connect to dcac=" + dcac + " status=" + status);
}
if (DBG) log("createDataConnection() X id=" + id + " dc=" + conn);
return dcac;
}
通过DataConnection的makeDataConnection方法新建一个DataConnection。
至此,DataConnection已经建立