在PhoneApp的初始化中,我们分析到,TelephonyNetworkFactory的初始化,最终会调用到DcTracker的requestNetwork方法
private void onNeedNetworkFor(Message msg) {
NetworkRequest networkRequest = (NetworkRequest)msg.obj;
boolean isApplicable = false;
LocalLog localLog = null;
if (TextUtils.isEmpty(networkRequest.networkCapabilities.getNetworkSpecifier())) {
// request only for the default network
localLog = mDefaultRequests.get(networkRequest);
if (localLog == null) {
localLog = new LocalLog(REQUEST_LOG_SIZE);
localLog.log("created for " + networkRequest);
mDefaultRequests.put(networkRequest, localLog);
isApplicable = mIsDefault;
}
} else {
localLog = mSpecificRequests.get(networkRequest);
if (localLog == null) {
localLog = new LocalLog(REQUEST_LOG_SIZE);
mSpecificRequests.put(networkRequest, localLog);
isApplicable = true;
}
}
if (mIsActive && isApplicable) {
String s = "onNeedNetworkFor";
localLog.log(s);
log(s + " " + networkRequest);
mDcTracker.requestNetwork(networkRequest, localLog);
} else {
String s = "not acting - isApp=" + isApplicable + ", isAct=" + mIsActive;
localLog.log(s);
log(s + " " + networkRequest);
}
}
而DcTracker的requestNetwork方法主要有
public void requestNetwork(NetworkRequest networkRequest, LocalLog log) {
final int apnId = ApnContext.apnIdForNetworkRequest(networkRequest);
final ApnContext apnContext = mApnContextsById.get(apnId);
log.log("DcTracker.requestNetwork for " + networkRequest + " found " + apnContext);
if (apnContext != null) apnContext.requestNetwork(networkRequest, log);
}
从前面DcTracker的初始化文章中,我们知道此处apnId为DctConstants.APN_DEFAULT_ID,那么ApnContext所对应的数据为
public ApnContext(Phone phone, String apnType, String logTag, NetworkConfig config,
DcTracker tracker) {
mPhone = phone;
mApnType = apnType;
mState = DctConstants.State.IDLE;
setReason(Phone.REASON_DATA_ENABLED);
mDataEnabled = new AtomicBoolean(false);
mDependencyMet = new AtomicBoolean(config.dependencyMet);
priority = config.priority;
LOG_TAG = logTag;
mDcTracker = tracker;
mRetryManager = new RetryManager(phone, apnType);
}
即apnType为default,priority为0,mDependencyMet为true
接下来,是调用了ApnContext的requestNetwork方法
public void requestNetwork(NetworkRequest networkRequest, LocalLog log) {
synchronized (mRefCountLock) {
if (mLocalLogs.contains(log) || mNetworkRequests.contains(networkRequest)) {
log.log("ApnContext.requestNetwork has duplicate add - " + mNetworkRequests.size());
} else {
mLocalLogs.add(log);
mNetworkRequests.add(networkRequest);
mDcTracker.setEnabled(apnIdForApnName(mApnType), true);
}
}
}
此方法主要是将当前的networkRequest加入到mNetworkRequests中进行管理,然后调用了DcTracker的setEnabled方法
由于mApnType为default,因此apnIdForApnName返回的是0,即DctConstants.APN_DEFAULT_ID
然后,我们来看下DcTracker的setEnabled方法
public void setEnabled(int id, boolean enable) {
Message msg = obtainMessage(DctConstants.EVENT_ENABLE_NEW_APN);
msg.arg1 = id;
msg.arg2 = (enable ? DctConstants.ENABLED : DctConstants.DISABLED);
sendMessage(msg);
}
由于此处传入的参数enable为true,因此,处理消息
case DctConstants.EVENT_ENABLE_NEW_APN:
onEnableApn(msg.arg1, msg.arg2);
break;
private void onEnableApn(int apnId, int enabled) {
ApnContext apnContext = mApnContextsById.get(apnId);
if (apnContext == null) {
loge("onEnableApn(" + apnId + ", " + enabled + "): NO ApnContext");
return;
}
// TODO change our retry manager to use the appropriate numbers for the new APN
if (DBG) log("onEnableApn: apnContext=" + apnContext + " call applyNewState");
applyNewState(apnContext, enabled == DctConstants.ENABLED, apnContext.getDependencyMet());
if ((enabled == DctConstants.DISABLED) &&
isOnlySingleDcAllowed(mPhone.getServiceState().getRilDataRadioTechnology()) &&
!isHigherPriorityApnContextActive(apnContext)) {
if(DBG) log("onEnableApn: isOnlySingleDcAllowed true & higher priority APN disabled");
// If the highest priority APN is disabled and only single
// data call is allowed, try to setup data call on other connectable APN.
setupDataOnConnectableApns(Phone.REASON_SINGLE_PDN_ARBITRATION);
}
}
直接调用DcTracker的applyNewState方法,其中各个参数为,第一个参数为ApnContext,第二个参数为true,第三个参数为true
private void applyNewState(ApnContext apnContext, boolean enabled, boolean met) {
boolean cleanup = false;
boolean trySetup = false;
String str ="applyNewState(" + apnContext.getApnType() + ", " + enabled +
"(" + apnContext.isEnabled() + "), " + met + "(" +
apnContext.getDependencyMet() +"))";
if (DBG) log(str);
apnContext.requestLog(str);
if (apnContext.isReady()) {
......
} else {
if (enabled && met) {
if (apnContext.isEnabled()) {
apnContext.setReason(Phone.REASON_DATA_DEPENDENCY_MET);
} else {
apnContext.setReason(Phone.REASON_DATA_ENABLED);
}
if (apnContext.getState() == DctConstants.State.FAILED) {
apnContext.setState(DctConstants.State.IDLE);
}
trySetup = true;
}
}
apnContext.setEnabled(enabled);
apnContext.setDependencyMet(met);
if (cleanup) cleanUpConnection(true, apnContext);
if (trySetup) {
apnContext.resetErrorCodeRetries();
trySetupData(apnContext);
}
}
由于是初始化,显然ApnContext.isReady()为false,isEnabled也为false,因此,走else分支
然后apnContext设置mDataEnabled为true,mDependencyMet为true
由于cleanup为false,而trySetup为true,因此会调用trySetupData方法
private boolean trySetupData(ApnContext apnContext) {
return trySetupData(apnContext, null);
}
private boolean trySetupData(ApnContext apnContext, ArrayList waitingApns) {
......
// Leo,一般无Emergency apn,因此此处为false
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.
// Leo,确认是否允许DataConnection建立
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 {
if (!apnContext.getApnType().equals(PhoneConstants.APN_TYPE_DEFAULT)
&& apnContext.isConnectable()) {
mPhone.notifyDataConnectionFailed(apnContext.getReason(), apnContext.getApnType());
}
notifyOffApnsOfAvailability(apnContext.getReason());
StringBuilder str = new StringBuilder();
str.append("trySetupData failed. apnContext = [type=" + apnContext.getApnType() +
", mState=" + apnContext.getState() + ", mDataEnabled=" +
apnContext.isEnabled() + ", mDependencyMet=" +
apnContext.getDependencyMet() + "] ");
if (!apnContext.isConnectable()) {
str.append("isConnectable = false. ");
}
if (!isDataAllowed) {
str.append("data not allowed: " + failureReason.getDataAllowFailReason() + ". ");
}
if (!isDataAllowedForApn(apnContext)) {
str.append("isDataAllowedForApn = false. RAT = " +
mPhone.getServiceState().getRilDataRadioTechnology());
}
if (!mDataEnabledSettings.isDataEnabled(checkUserDataEnabled)) {
str.append("isDataEnabled(" + checkUserDataEnabled + ") = false. " +
"isInternalDataEnabled = " + mDataEnabledSettings.isInternalDataEnabled() +
", userDataEnabled = " + mDataEnabledSettings.isUserDataEnabled() +
", isPolicyDataEnabled = " + mDataEnabledSettings.isPolicyDataEnabled() +
", isCarrierDataEnabled = " +
mDataEnabledSettings.isCarrierDataEnabled());
}
if (isEmergency()) {
str.append("emergency = true");
}
if (DBG) log(str.toString());
apnContext.requestLog(str.toString());
return false;
}
}
从这个方法,我们可以看到,判断是否能够建立数据连接,需要满足几个条件,就是if部分的判断,从前面的说明,我们知道,mEmergencyApn为false,那么我们来分析一下isDataAllowed
首先我们看下isDataAllowed方法
private boolean isDataAllowed(DataAllowFailReason failureReason) {
final boolean internalDataEnabled;
internalDataEnabled = mDataEnabledSettings.isInternalDataEnabled();
boolean attachedState = mAttached.get();
boolean desiredPowerState = mPhone.getServiceStateTracker().getDesiredPowerState();
boolean radioStateFromCarrier = mPhone.getServiceStateTracker().getPowerStateFromCarrier();
int radioTech = mPhone.getServiceState().getRilDataRadioTechnology();
if (radioTech == ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN) {
desiredPowerState = true;
radioStateFromCarrier = true;
}
IccRecords r = mIccRecords.get();
boolean recordsLoaded = false;
if (r != null) {
recordsLoaded = r.getRecordsLoaded();
if (DBG && !recordsLoaded) log("isDataAllowed getRecordsLoaded=" + recordsLoaded);
}
int dataSub = SubscriptionManager.getDefaultDataSubscriptionId();
boolean defaultDataSelected = SubscriptionManager.isValidSubscriptionId(dataSub);
PhoneConstants.State state = PhoneConstants.State.IDLE;
// Note this is explicitly not using mPhone.getState. See b/19090488.
// mPhone.getState reports the merge of CS and PS (volte) voice call state
// but we only care about CS calls here for data/voice concurrency issues.
// Calling getCallTracker currently gives you just the CS side where the
// ImsCallTracker is held internally where applicable.
// This should be redesigned to ask explicitly what we want:
// voiceCallStateAllowDataCall, or dataCallAllowed or something similar.
if (mPhone.getCallTracker() != null) {
state = mPhone.getCallTracker().getState();
}
if (failureReason != null) failureReason.clearAllReasons();
if (!(attachedState || mAutoAttachOnCreation.get())) {
if(failureReason == null) return false;
failureReason.addDataAllowFailReason(DataAllowFailReasonType.NOT_ATTACHED);
}
if (!recordsLoaded) {
if(failureReason == null) return false;
failureReason.addDataAllowFailReason(DataAllowFailReasonType.RECORD_NOT_LOADED);
}
if (state != PhoneConstants.State.IDLE &&
!mPhone.getServiceStateTracker().isConcurrentVoiceAndDataAllowed()) {
if(failureReason == null) return false;
failureReason.addDataAllowFailReason(DataAllowFailReasonType.INVALID_PHONE_STATE);
failureReason.addDataAllowFailReason(
DataAllowFailReasonType.CONCURRENT_VOICE_DATA_NOT_ALLOWED);
}
if (!internalDataEnabled) {
if(failureReason == null) return false;
failureReason.addDataAllowFailReason(DataAllowFailReasonType.INTERNAL_DATA_DISABLED);
}
if (!defaultDataSelected) {
if(failureReason == null) return false;
failureReason.addDataAllowFailReason(
DataAllowFailReasonType.DEFAULT_DATA_UNSELECTED);
}
if (mPhone.getServiceState().getDataRoaming() && !getDataOnRoamingEnabled()) {
if(failureReason == null) return false;
failureReason.addDataAllowFailReason(DataAllowFailReasonType.ROAMING_DISABLED);
}
if (mIsPsRestricted) {
if(failureReason == null) return false;
failureReason.addDataAllowFailReason(DataAllowFailReasonType.PS_RESTRICTED);
}
if (!desiredPowerState) {
if(failureReason == null) return false;
failureReason.addDataAllowFailReason(DataAllowFailReasonType.UNDESIRED_POWER_STATE);
}
if (!radioStateFromCarrier) {
if(failureReason == null) return false;
failureReason.addDataAllowFailReason(DataAllowFailReasonType.RADIO_DISABLED_BY_CARRIER);
}
return failureReason == null || !failureReason.isFailed();
}
从DcTracker的初始化中,我们可以得出结论,mAttach.get()为false,而mAutoAttachOnCreation.get()也为false,因此,此处的第一个if语句,返回的即为true,也就是说failureReason的isFailed()方法返回的即为true,因此isDataAllowed方法返回了false
然后通过对于其他的参数分析,均能够得出一个结论,即isDataAllowed变量的结果为false,然后trySetupData方法,只能走else分支,然后结束
也就是说,这个PhoneApp初始化的过程,并不能建立数据连接
那么数据连接是通过什么来建立的呢?
下一篇,我们来分析下,数据连接的真正建立流程