美文网首页
APN的基础知道-安卓

APN的基础知道-安卓

作者: DD_Dog | 来源:发表于2019-12-23 15:16 被阅读0次

    APN的基础知识

    在安卓开发中,尤其是网络开发,可能会经常接触到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是质询握手认证协议,是三次握手机制。


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

    MCC和MNC: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

    1. 创建数据库
      由于添加了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:-");
    }
    
    1. 读取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);
    }
    
    1. 设置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, mvnoMmsApn
                             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());
         }
    }
    

    各个国家mccmnc的查询

    相关文章

      网友评论

          本文标题:APN的基础知道-安卓

          本文链接:https://www.haomeiwen.com/subject/yziznctx.html