APN基础常识

一.APN的简介

APN的完整说明在3GPP规范TS23.003 Clause 9中进行了详细定义。
MCCMNC的定义在3GPP规范TS23.003 Clause 2的IMSI定义中。

APN在GPRS骨干网中用来标识要使用的外部PDN(Packet data network,分组数据网,即常说的Internet),在GPRS网络中代表外部数据网络的总称。

APN由以下两部分组成:

APN网络标识:
是用户通过GGSN/PGW(Gateway GPRS Support Node,GPRS网关支持节点/PDN Gateway ,分组数据网网关)可连接到外部网络的标识,该标识由网络运营者分配给ISP(Internet Service Provider,因特网业务提供者)或公司,与其固定Internet域名一致,是APN的必选组成部分。例如 , 定义移动用户通过该接入某公司的企业网,则APN的网络标识可以规划为“www.ABC123.com”。
APN运营者标识:
用于标识GGSN/PGW所归属的网络,是APN的可选组成部分。其形式为“MNCxxxx.MCCyyyy.gprs”(3G网络中),或者“MNCxxxx.MCCyyyy.3gppnetwork.org(4G网络中)。APN实际上就是对一个外部PDN的标识,这些PDN包括企业内部网、Internet、WAP网站、行业内部网等专用网络。

二.Apn参数的组成

例:移动apn,把所有的属性都放在一起如下

apn carrier=”中国移动彩信 (China Mobile)”
mcc=”460”
mnc=”00”
apn=”cmwap”
proxy=”10.0.0.172”
port=”80”
mmsc=”http://mmsc.monternet.com”
mmsproxy=”10.0.0.172”
mmsport=”80”
user=”mms”
password=”mms”
type=”mms”
authtype=”1”
protocol=”IPV4V6”
/>
其对应的属性定义如下:

Carrier:apn的名字,可为空,只用来显示apn列表中此apn的显示名字。
Mcc:由三位数组成。 用于识别移动用户的所在国家;
Mnc:由两位或三位组成。 用于识别移动用户的归属PLMN。 MNC的长度(两位或三位数)取决于MCC的值。
Apn:APN网络标识(接入点名称),是APN参数中的必选组成部分。此标识由运营商分配。
Proxy:代理服务器的地址
Port:代理服务器的端口号
Mmsc:MMS中继服务器/多媒体消息业务中心,是彩信的交换服务器。
Mmsproxy:彩信代理服务器的地址
Mmsport:彩信代理服务器的端口号
Protocol:支持的协议,不配置默认为IPV4。
User:用户
Password:密码
Authtype:apn的认证协议,PAP为口令认证协议,是二次握手机制。CHAP是质询握手认证协议,是三次握手机制。

None0
PAP1
CHAP2
PAP or CHAP3

Type: apn的接入点类型

Default默认网络连接
Mms彩信专用连接,此连接与default类似,用于与载体的多媒体信息服务器对话的应用程序
Supl是Secure User Plane Location“安全用户面定位”的简写,此连接与default类似,用于帮助定位设备与载体的安全用户面定位服务器对话的应用程序
Dun Dial Up Networking拨号网络的简称,此连接与default连接类似,用于执行一个拨号网络网桥,使载体能知道拨号网络流量的应用程序
Hipri 高优先级网络,与default类似,但路由设置不同。只有当进程访问移动DNS服务器,并明确要求使用requestRouteToHost(int, int)才会使用此连接

注意:此表中的数据连接优先级是由低到高,即default数据连接的优先级最低,而hipri数据连接的优先级最高。比如:手机上网聊天,建立的是default数据连接。如果此时接到一条彩信,由于彩信的数据连接是mms,优先级比default高,所以会先断开default数据连接,建立mms数据连接,让手机先收到彩信。所以收发彩信的同时不能上网。(单条pdp连接的情况)

注:mnc的位数由mcc决定。比如,墨西哥334020,此国家的mnc为020,mccmnc的值都固定在了SIM卡保存的IMSI中,配置apn参数时mnc不可简洁为20,否则apn列表中将读取不到此国家的334020运营商的参数。

三.Apn的存储以及初始化

apn在手机中的存储:

apn文件:System/etc/apn-conf.xml
apn数据存储的数据库:/data/data/com.android.providers.telephony/databases/ telephony.db
Carriers表

apn的初始化:

在启动手机时,需要初始化telephony.db数据库,这时候会读取手机目录System/etc/apn-conf.xml并把其中的内容加入到Carriers表中。以后查询有关apn的配置参数都是从Carriers表中取出。

创建并初始化Carriers表:
packages/providers/TelephonyProvider/src/com/android/providers/telephony/TelephonyProvider.java

内部类:DatabaseHelper.java

//创建数据库
由于添加了UNIQUE 约束条件,如果两个差不多的apn参数满足约束条件内的属性都相等,那么认为是同一组apn参数,将不会重复插入到数据库。

        private void createCarriersTable(SQLiteDatabase db, String tableName) {
            // Set up the database schema
            if (DBG) log("dbh.createCarriersTable start");
            String columns = "(_id INTEGER PRIMARY KEY," +
                    NAME + " TEXT DEFAULT ''," +
                    NUMERIC + " TEXT DEFAULT ''," +
                    MCC + " TEXT DEFAULT ''," +
                    MNC + " TEXT DEFAULT ''," +
                    APN + " TEXT DEFAULT ''," +
                    USER + " TEXT DEFAULT ''," +
                    SERVER + " TEXT DEFAULT ''," +
                    PASSWORD + " TEXT DEFAULT ''," +
                    PROXY + " TEXT DEFAULT ''," +
                    PORT + " TEXT DEFAULT ''," +
                    MMSPROXY + " TEXT DEFAULT ''," +
                    MMSPORT + " TEXT DEFAULT ''," +
                    MMSC + " TEXT DEFAULT ''," +
                    AUTH_TYPE + " INTEGER DEFAULT -1," +
                    TYPE + " TEXT DEFAULT ''," +
                    CURRENT + " INTEGER," +
                    SOURCE_TYPE + " INTEGER DEFAULT 0," +
                    CSD_NUM + " TEXT DEFAULT ''," +
                    PROTOCOL + " TEXT DEFAULT IP," +
                    ROAMING_PROTOCOL + " TEXT DEFAULT IP,";

            /// M: add for OMACP service
            if (OMACP_SUPPORT) {
                columns += OMACP_ID + " TEXT DEFAULT ''," +
                        NAP_ID + " TEXT DEFAULT ''," +
                        PROXY_ID + " TEXT DEFAULT '',";
            }

            columns += CARRIER_ENABLED + " BOOLEAN DEFAULT 1," +
                    BEARER + " INTEGER DEFAULT 0," +
                    BEARER_BITMASK + " INTEGER DEFAULT 0," +
                    SPN + " TEXT DEFAULT ''," +
                    IMSI + " TEXT DEFAULT ''," +
                    PNN +  " TEXT DEFAULT ''," +
                    PPP +  " TEXT DEFAULT ''," +
                    MVNO_TYPE + " TEXT DEFAULT ''," +
                    MVNO_MATCH_DATA + " TEXT DEFAULT '',";

            columns += SUBSCRIPTION_ID + " INTEGER DEFAULT " +
                    SubscriptionManager.INVALID_SUBSCRIPTION_ID + "," +
                    PROFILE_ID + " INTEGER DEFAULT 0," +
                    MODEM_COGNITIVE + " BOOLEAN DEFAULT 0," +
                    MAX_CONNS + " INTEGER DEFAULT 0," +
                    WAIT_TIME + " INTEGER DEFAULT 0," +
                    MAX_CONNS_TIME + " INTEGER DEFAULT 0," +
                    MTU + " INTEGER DEFAULT 0," +
                    EDITED + " INTEGER DEFAULT " + UNEDITED + "," +
                    USER_VISIBLE + " BOOLEAN DEFAULT 1, " +
                    USER_EDITABLE + " BOOLEAN DEFAULT 1," +
                    // Uniqueness collisions are used to trigger merge code so if a field is listed
                    // here it means we will accept both (user edited + new apn_conf definition)
                    // Columns not included in UNIQUE constraint: name, current, edited,
                    // user, server, password, authtype, type, protocol, roaming_protocol, sub_id,
                    // modem_cognitive, max_conns, wait_time, max_conns_time, mtu, bearer_bitmask,
                    // user_visible
                    "UNIQUE (" + TextUtils.join(", ", CARRIERS_UNIQUE_FIELDS) + "));";
            db.execSQL("CREATE TABLE " + tableName + columns);

            db.execSQL("DROP TABLE IF EXISTS " + CARRIERS_DM_TABLE);
            db.execSQL("CREATE TABLE " + CARRIERS_DM_TABLE + columns);
            if (DBG) log("dbh.createCarriersTable:-");
        }                                                    

//读取apns-conf.xml文件,并初始化Carriers表。

        private void initDatabase(SQLiteDatabase db) {
            if (VDBG) log("dbh.initDatabase:+ db=" + db);
            // Read internal APNS data
            Resources r = mContext.getResources();
            XmlResourceParser parser = r.getXml(com.android.internal.R.xml.apns);
            int publicversion = -1;
            try {
                XmlUtils.beginDocument(parser, "apns");
                publicversion = Integer.parseInt(parser.getAttributeValue(null, "version"));
                loadApns(db, parser);
            } catch (Exception e) {
                loge("Got exception while loading APN database." + e);
            } finally {
                parser.close();
            }

            // Read external APNS data (partner-provided)
            XmlPullParser confparser = null;
            File confFile = getApnConfFile();

            FileReader confreader = null;
            if (DBG) log("confFile = " + confFile);
            try {
                confreader = new FileReader(confFile);
                confparser = Xml.newPullParser();
                confparser.setInput(confreader);
                XmlUtils.beginDocument(confparser, "apns");

                // Sanity check. Force internal version and confidential versions to agree
                int confversion = Integer.parseInt(confparser.getAttributeValue(null, "version"));
                if (publicversion != confversion) {
                    log("initDatabase: throwing exception due to version mismatch");
                    throw new IllegalStateException("Internal APNS file version doesn't match "
                            + confFile.getAbsolutePath());
                }

                db.beginTransaction();
                try {
                    loadApns(db, confparser);
                    db.setTransactionSuccessful();
                } finally {
                    db.endTransaction();
                }
            } catch (FileNotFoundException e) {
                // It's ok if the file isn't found. It means there isn't a confidential file
                // Log.e(TAG, "File not found: '" + confFile.getAbsolutePath() + "'");
            } catch (Exception e) {
                loge("initDatabase: Exception while parsing '" + confFile.getAbsolutePath() + "'" +
                        e);
            } finally {
                // Get rid of user/carrier deleted entries that are not present in apn xml file.
                // Those entries have edited value USER_DELETED/CARRIER_DELETED.
                if (VDBG) {
                    log("initDatabase: deleting USER_DELETED and replacing "
                            + "DELETED_BUT_PRESENT_IN_XML with DELETED");
                }

                // Delete USER_DELETED
                db.delete(CARRIERS_TABLE, IS_USER_DELETED + " or " + IS_CARRIER_DELETED, null);

                // Change USER_DELETED_BUT_PRESENT_IN_XML to USER_DELETED
                ContentValues cv = new ContentValues();
                cv.put(EDITED, USER_DELETED);
                db.update(CARRIERS_TABLE, cv, IS_USER_DELETED_BUT_PRESENT_IN_XML, null);

                // Change CARRIER_DELETED_BUT_PRESENT_IN_XML to CARRIER_DELETED
                cv = new ContentValues();
                cv.put(EDITED, CARRIER_DELETED);
                db.update(CARRIERS_TABLE, cv, IS_CARRIER_DELETED_BUT_PRESENT_IN_XML, null);

                if (confreader != null) {
                    try {
                        confreader.close();
                    } catch (IOException e) {
                        // do nothing
                    }
                }

                // Update the stored checksum
                setApnConfChecksum(getChecksum(confFile));
            }
            if (VDBG) log("dbh.initDatabase:- db=" + db);

        }                                            

设置APN:
packages/apps/Settings/src/com/android/settings/ApnSettings.java
查询数据库Carriers表中的数据:

    private void fillList() {
        final TelephonyManager tm = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
        String mccmnc = mSubscriptionInfo == null ? "" : tm.getSimOperator
                (mSubscriptionInfo != null ? mSubscriptionInfo.getSubscriptionId()
                : SubscriptionManager.INVALID_SUBSCRIPTION_ID);
        /// M: for plug-in @{
        // use mcc&mnc in IMPI to query apn.
        Log.d(TAG, "before plugin, mccmnc = " + mccmnc);
        mccmnc = mApnExt.getOperatorNumericFromImpi(mccmnc,
                SubscriptionManager.getPhoneId(mSubscriptionInfo.getSubscriptionId()));
        /// @}
        Log.d(TAG, "mccmnc = " + mccmnc);
       /*
       StringBuilder where = new StringBuilder("numeric=\"" + mccmnc +
                "\" AND NOT (type='ia' AND (apn=\"\" OR apn IS NULL)) AND user_visible!=0");
        */

        String where = "numeric=\"" + mccmnc + "\"";
        /// M: for [C2K APN Customization] @{
        if (mSubscriptionInfo != null) {
            int subId = mSubscriptionInfo.getSubscriptionId();
            if (CdmaUtils.isSupportCdma(subId)) {
                where = CdmaApnSetting.customizeQuerySelectionforCdma(where, mccmnc, subId);
            }
        }
        /// @}

        where += " AND NOT (type='ia' AND (apn=\"\" OR apn IS NULL)) AND user_visible!=0";
        /// M: for VoLTE, do not show ims apn for non-VoLTE project @{
        /*
        if (mHideImsApn) {
            where.append(" AND NOT (type='ims')");
        }
        */

        //if (!FeatureOption.MTK_VOLTE_SUPPORT || mHideImsApn) {
            where += " AND NOT (type='ims' OR type='ia,ims')";
        //}

        /// @}
        /// M: for plug-in
        where = mApnExt.getFillListQuery(where, mccmnc);
        Log.d(TAG, "fillList where: " + where);
        String order = mApnExt.getApnSortOrder(Telephony.Carriers.DEFAULT_SORT_ORDER);
        order = "_id asc";
        Log.d(TAG, "fillList sort: " + order);
        Cursor cursor = getContentResolver().query(
                Telephony.Carriers.CONTENT_URI,
                new String[] { "_id", "name", "apn", "type", "mvno_type", "mvno_match_data",
                        "sourcetype" }, where.toString(), null, order);

        if (cursor != null) {
            Log.d(TAG, "fillList, cursor count: " + cursor.getCount());
            IccRecords r = null;
            if (mUiccController != null && mSubscriptionInfo != null) {
                r = mUiccController.getIccRecords(SubscriptionManager.getPhoneId(
                        mSubscriptionInfo.getSubscriptionId()), UiccController.APP_FAM_3GPP);
            }
            PreferenceGroup apnList = (PreferenceGroup) findPreference("apn_list");
            apnList.removeAll();

            /// M: for plug-in, use Preference instead ApnPreference for the
            // convenience of plug-in side
            ArrayList<Preference> mnoApnList = new ArrayList<Preference>();
            ArrayList<Preference> mvnoApnList = new ArrayList<Preference>();
            ArrayList<Preference> mnoMmsApnList = new ArrayList<Preference>();
            ArrayList<Preference> mvnoMmsApnList = new ArrayList<Preference>();

            mSelectedKey = getSelectedApnKey();
            cursor.moveToFirst();
            while (!cursor.isAfterLast()) {
                String name = cursor.getString(NAME_INDEX);
                String apn = cursor.getString(APN_INDEX);
                String key = cursor.getString(ID_INDEX);
                String type = cursor.getString(TYPES_INDEX);
                String mvnoType = cursor.getString(MVNO_TYPE_INDEX);
                String mvnoMatchData = cursor.getString(MVNO_MATCH_DATA_INDEX);
                /// M: check source type, some types are not editable
                int sourcetype = cursor.getInt(SOURCE_TYPE_INDEX);
                /// M: skip specific APN type
                if(shouldSkipApn(type)) {
                    cursor.moveToNext();
                    continue;
                }
                /// M: for plug-in
                name = mApnExt.updateApnName(name, sourcetype);
                ApnPreference pref = new ApnPreference(getPrefContext());

                pref.setKey(key);
                pref.setTitle(name);
                pref.setSummary(apn);
                pref.setPersistent(false);
                pref.setOnPreferenceChangeListener(this);
                pref.setSubId(mSubscriptionInfo.getSubscriptionId());

                /// M: for [Read Only APN]
                pref.setApnEditable(mApnExt.isAllowEditPresetApn(type, apn, mccmnc, sourcetype));
                pref.setSubId(mSubscriptionInfo == null ? null : mSubscriptionInfo
                        .getSubscriptionId());

                /// M: for ALPS02500557, do not select emergency APN
                boolean selectable = ((type == null) || (!type.equals("mms")
                        && !type.equals("ia") && !type.equals("ims") && !type.equals("emergency")))
                        /// M: for plug-in
                        && mApnExt.isSelectable(type);
                pref.setSelectable(selectable);
                Log.d(TAG, "mSelectedKey = " + mSelectedKey + " key = " + key + " name = " + name +
                        " selectable=" + selectable);
                if (selectable) {
                    /// M: select prefer APN later, as the apn list are not solid now @{
                    /*
                    if ((mSelectedKey != null) && mSelectedKey.equals(key)) {
                        pref.setChecked();
                    }
                    */
                    /// @}
                    addApnToList(pref, mnoApnList, mvnoApnList, r, mvnoType, mvnoMatchData);
                    /// M: For CT feature,when apns-conf.xml add type extra value "supl",
                    //     selectable maybe ture when 46011 mms, so need this method.
                    mApnExt.customizeUnselectableApn(type, mvnoType, mvnoMatchData, mnoApnList, mvnoApnList,
                            mSubscriptionInfo == null ? null : mSubscriptionInfo
                                    .getSubscriptionId());
                } else {
                    addApnToList(pref, mnoMmsApnList, mvnoMmsApnList, r, mvnoType, mvnoMatchData);
                    /// M: for plug-in
                    mApnExt.customizeUnselectableApn(type, mvnoType, mvnoMatchData, mnoMmsApnList, mvnoMmsApnList,
                            mSubscriptionInfo == null ? null : mSubscriptionInfo
                                    .getSubscriptionId());
                }
                cursor.moveToNext();
            }
            cursor.close();

            if (!mvnoApnList.isEmpty()) {
                mnoApnList = mvnoApnList;
                mnoMmsApnList = mvnoMmsApnList;

                // Also save the mvno info
            }

            for (Preference preference : mnoApnList) {
                apnList.addPreference(preference);
            }
            for (Preference preference : mnoMmsApnList) {
                apnList.addPreference(preference);
            }

            /// M: always set a prefer APN
            setPreferApnChecked(mnoApnList);

            /// M: update screen enable state according to airplane mode, SIM radio status, etc.
            updateScreenEnableState(getActivity());
        }
    }                                                                                                

packages/apps/Settings/src/com/android/settings/ApnEditor.java

各个国家mccmnc的查询:
http://www.gpsspg.com/bs/mnc.htm

  • 28
    点赞
  • 203
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值