Android Data Analyse(3)--APN & ApnSetting & ApnContext

APN

定义
APN (access point name) 简单的可以理解为数据上网的接入点名称,是访问数据的必须要配置的参数。该参数的配置直接决定了访问数据的接入方式。


参数

  <apn carrier="中国移动 (China Mobile) WAP"
      mcc="460"
      mnc="00"
      apn="cmwap"
      proxy="10.0.0.172"
      port="80"
      type="default,supl"
  />
名称 说明
carrier 该APN的名称(在手机上可以看到)
mccmnc 手机的mccmnc
apn 接入点
proxy 代理
port 端口
type 该条apn可以入网的类型

配置

apn 由google定义了一套可供各运营商使用的默认配置,其默认存放位置在device/sample/etc/apns-full-conf.xml里。编译后会copy到system/etc/apns-conf.xml.针对不同的运营商需求,可以在apns-full-conf.xml里更改。
在手机中,apn存在于telephony.db中。具体位置为:content://telephony/carriers


加载
在device 检测到simcard load完成后,经过一系列的调用:

    protected void onRecordsLoadedOrSubIdChanged() {
    ...
        createAllApnList();//从数据库中获取所有符合标准的apn
        setInitialAttachApn();//设置初始accach的apn
     ...
    }
    /**
     * Based on the sim operator numeric, create a list for all possible
     * Data Connections and setup the preferredApn.
     */
    protected void createAllApnList() {
        mMvnoMatched = false;//虚拟运营商相关的,尚未遇到过
        mAllApnSettings = new ArrayList<ApnSetting>();
        IccRecords r = mIccRecords.get();
        String operator = mPhone.getOperatorNumeric();
        if (operator != null) {
            String selection = "numeric = '" + operator + "'";
            String orderBy = "_id";
            // query only enabled apn.
            // carrier_enabled : 1 means enabled apn, 0 disabled apn.
            // selection += " and carrier_enabled = 1";
            if (DBG) log("createAllApnList: selection=" + selection);

            //通过mccmnc筛选出apn集合
            Cursor cursor = mPhone.getContext().getContentResolver().query(
                    Telephony.Carriers.CONTENT_URI, null, selection, null, orderBy);

            if (cursor != null) {
                if (cursor.getCount() > 0) {
                //得到所有合适的apn
                    mAllApnSettings = createApnList(cursor);
                }
                cursor.close();
            }
        }

        //添加Emergency APN settings
        addEmergencyApnSetting();

        //去除重复的apn
        dedupeApnSettings();

        if (mAllApnSettings.isEmpty()) {
            if (DBG) log("createAllApnList: No APN found for carrier: " + operator);
            mPreferredApn = null;
            // TODO: What is the right behavior?
            //notifyNoData(DataConnection.FailCause.MISSING_UNKNOWN_APN);
        } else {
            mPreferredApn = getPreferredApn();
            if (mPreferredApn != null && !mPreferredApn.numeric.equals(operator)) {
                mPreferredApn = null;
                setPreferredApn(-1);
            }
            if (DBG) log("createAllApnList: mPreferredApn=" + mPreferredApn);
        }
        if (DBG) log("createAllApnList: X mAllApnSettings=" + mAllApnSettings);

        setDataProfilesAsNeeded();
    }


ApnSetting

ApnSetting 可以简单看成是APN的构造函数(?),在查询数据库时,主要以ApnSetting 形式存储。其参数分别对应着telephony.db carrier表里的各项。
构造函数


    public ApnSetting(int id, String numeric, String carrier, String apn,
            String proxy, String port,
            String mmsc, String mmsProxy, String mmsPort,
            String user, String password, int authType, String[] types,
            String protocol, String roamingProtocol, boolean carrierEnabled, int bearer,
            int bearerBitmask, int profileId, boolean modemCognitive, int maxConns, int waitTime,
            int maxConnsTime, int mtu, String mvnoType, String mvnoMatchData) {
        this.id = id; //数据库里的标识ID
        this.numeric = numeric; // mccmnc
        this.carrier = carrier; //该apn的名称(即在settings里显示)
        this.apn = apn; //接入点
        this.proxy = proxy; //apn 的代理
        this.port = port; //apn 的端口号
        this.mmsc = mmsc; //彩信中心地址
        this.mmsProxy = mmsProxy; //彩信代理
        this.mmsPort = mmsPort; //彩信端口
        this.user = user; //没看懂(to be update)
        this.password = password; //没看懂(to be update)
        this.authType = authType; //没看懂(to be update)
        this.types = new String[types.length]; //该apn适用的data类型
        for (int i = 0; i < types.length; i++) {
            this.types[i] = types[i].toLowerCase(Locale.ROOT);
        }
        this.protocol = protocol;
        this.roamingProtocol = roamingProtocol;
        this.carrierEnabled = carrierEnabled;
        this.bearer = bearer;//能够处理的网络类型(?)
        this.bearerBitmask = (bearerBitmask | ServiceState.getBitmaskForTech(bearer));
        this.profileId = profileId;
        this.modemCognitive = modemCognitive;
        this.maxConns = maxConns;
        this.waitTime = waitTime;
        this.maxConnsTime = maxConnsTime;
        this.mtu = mtu;
        this.mvnoType = mvnoType;
        this.mvnoMatchData = mvnoMatchData;

    }

重点接口


    /**
     * 判断传递过来的type是否能够处理。
     * 通常在不同运营商上有不同的需求,这块需要特殊处理
     */
    public boolean canHandleType(String type) {
        if (!carrierEnabled) return false;
        for (String t : types) {
            // DEFAULT handles all, and HIPRI is handled by DEFAULT
            if (t.equalsIgnoreCase(type) ||
                    t.equalsIgnoreCase(PhoneConstants.APN_TYPE_ALL) ||
                    (t.equalsIgnoreCase(PhoneConstants.APN_TYPE_DEFAULT) &&
                    type.equalsIgnoreCase(PhoneConstants.APN_TYPE_HIPRI))) {
                return true;
            }
        }
        return false;
    }


ApnContext

APN & ApnSetting 均为配置参数,而ApnContext 则是操作APN or ApnSetting. 在Dctracker 或者DataConnection 等跟数据相关主要的相关类中,主要操作ApnContext来读取或设置APN相关信息。

常用的接口

接口 返回值 说明
getApnSetting ApnSetting 返回当前所有APN
getApnType String 返回当前APN类型
getState DctConstants.State 返回该条apn对应网络的状态
isConnectedOrConnecting boolean 返回当前apn对应的网络是否连接

系统调用


    /**
     * 判断传递过来的type 是否允许访问数据
     */
    public boolean isDataPossible(String apnType) {
        ApnContext apnContext = mApnContexts.get(apnType);
        if (apnContext == null) {
            return false;
        }
        boolean apnContextIsEnabled = apnContext.isEnabled();
        DctConstants.State apnContextState = apnContext.getState();
        boolean apnTypePossible = !(apnContextIsEnabled &&
                (apnContextState == DctConstants.State.FAILED));
        boolean isEmergencyApn = apnContext.getApnType().equals(PhoneConstants.APN_TYPE_EMERGENCY);
        // Set the emergency APN availability status as TRUE irrespective of conditions checked in
        // isDataAllowed() like IN_SERVICE, MOBILE DATA status etc.
        boolean dataAllowed = isEmergencyApn || isDataAllowed(null);
        boolean possible = dataAllowed && apnTypePossible;

        if ((apnContext.getApnType().equals(PhoneConstants.APN_TYPE_DEFAULT)
                    || apnContext.getApnType().equals(PhoneConstants.APN_TYPE_IA))
                && (mPhone.getServiceState().getRilDataRadioTechnology()
                == ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN)) {
            log("Default data call activation not possible in iwlan.");
            possible = false;
        }

        if (VDBG) {
            log(String.format("isDataPossible(%s): possible=%b isDataAllowed=%b " +
                            "apnTypePossible=%b apnContextisEnabled=%b apnContextState()=%s",
                    apnType, possible, dataAllowed, apnTypePossible,
                    apnContextIsEnabled, apnContextState));
        }
        return possible;
    }

猜你喜欢

转载自blog.csdn.net/Clear_ws/article/details/78186190