(N)Telephony分析(六)之DcTracker的requestNetwork分析

在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初始化的过程,并不能建立数据连接

那么数据连接是通过什么来建立的呢?

下一篇,我们来分析下,数据连接的真正建立流程

你可能感兴趣的:(Telephony分析)