APN的基础知道-安卓

2019-12-23  本文已影响0人  DD_Dog

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” 
/> 

其对应的属性定义如下:

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的查询

上一篇下一篇

猜你喜欢

热点阅读