apn管理

来源:互联网 发布:mac acl 编辑:程序博客网 时间:2024/05/18 03:54

1、简介:

每个运营商都有特定的一些apn,android 系统怎么识别和管理这些apn,本文将对这个问题做一些讨论和研究。

2、分析

2.1 流程简介

神秘的apn到底是怎么一回事,为什么插一张移动卡就会有China Mobile 的3个apn,这些数据怎么获取的?如下图所示:

 

流程简介:
1)系统启动的时候会将apns.xml 、apns-conf.xml中定义的运营商的apn加载到数据中去;
2)在系统设置里面会根据当前插入的sim卡去查询sim卡运营商相关的apn,并显示出来。
说明:从流程的第一步可以看出运营商的apn都定义在apns.xml 、apns-conf.xml这两个xml中,如果要让系统支持某运营商,我们必须添加相应的apn到xml中,否则系统将不会查询到该卡的apn,会影响用户的上网等功能。

2.2涉及的文件

[plain] view plaincopy
  1. com.android.providers.telephony.TelephonyProvider  
  2. etc/apns-conf.xml  
  3. /framework/base/core/res/res/apns.xml  
  4. com.android.settings.ApnSettings  

2.3 加载数据到数据库

 加载数据到数据库是在TelephonyProvider中完成的,该类是一个ContentProvider,ContentProvider就不用我在这给大家介绍啦yixia ;
1)首先是创建对应的数据库表,以下是其核心代码:

[plain] view plaincopy
  1. @Override  
  2. public void onCreate(SQLiteDatabase db) {  
  3.     // Set up the database schema  
  4.     db.execSQL("CREATE TABLE " + CARRIERS_TABLE +  
  5.         "(_id INTEGER PRIMARY KEY," +  
  6.             "name TEXT," +  
  7.             "numeric TEXT," +  
  8.             "mcc TEXT," +  
  9.             "mnc TEXT," +  
  10.             "apn TEXT," +  
  11.             "user TEXT," +  
  12.             "server TEXT," +  
  13.             "password TEXT," +  
  14.             "proxy TEXT," +  
  15.             "port TEXT," +  
  16.             "mmsproxy TEXT," +  
  17.             "mmsport TEXT," +  
  18.             "mmsc TEXT," +  
  19.             "authtype INTEGER," +  
  20.             "type TEXT," +  
  21.             "ipversion TEXT," +  
  22.             "current INTEGER);");  
  23.   
  24.     initDatabase(db);  
  25. }  
2)加载数据通过,initDatabase()方法;该方法是将各个google定义的内部的apn以及用户定制的apn添加到数据库;以下是其核心代码:

[plain] view plaincopy
  1. private void initDatabase(SQLiteDatabase db) {  
  2.             // Read internal APNS data  
  3.             Resources r = mContext.getResources();  
  4.             XmlResourceParser parser = r.getXml(com.android.internal.R.xml.apns);  
  5.             int publicversion = -1;  
  6.             try {  
  7.                 XmlUtils.beginDocument(parser, "apns");  
  8.                 publicversion = Integer.parseInt(parser.getAttributeValue(null, "version"));  
  9.                 loadProfiles(db, parser);  
  10.             } catch (Exception e) {  
  11.                 Log.e(TAG, "Got exception while loading APN database.", e);  
  12.             } finally {  
  13.                 parser.close();  
  14.             }  
  15.            // Read external APNS data (partner-provided)  
  16.             XmlPullParser confparser = null;  
  17.             // Environment.getRootDirectory() is a fancy way of saying ANDROID_ROOT or "/system".  
  18.             File confFile = new File(Environment.getRootDirectory(), PARTNER_APNS_PATH);  
  19.             FileReader confreader = null;  
  20.             try {  
  21.                 confreader = new FileReader(confFile);  
  22.                 confparser = Xml.newPullParser();  
  23.                 confparser.setInput(confreader);  
  24.                 XmlUtils.beginDocument(confparser, "apns");  
  25.   
  26.                 // Sanity check. Force internal version and confidential versions to agree  
  27.                 int confversion = Integer.parseInt(confparser.getAttributeValue(null, "version"));  
  28.                 if (publicversion != confversion) {  
  29.                     throw new IllegalStateException("Internal APNS file version doesn't match "  
  30.                             + confFile.getAbsolutePath());  
  31.                 }  
  32.   
  33.                 loadProfiles(db, confparser);  
  34.             } catch (FileNotFoundException e) {  
  35.                 // It's ok if the file isn't found. It means there isn't a confidential file  
  36.                 // Log.e(TAG, "File not found: '" + confFile.getAbsolutePath() + "'");  
  37.             } catch (Exception e) {  
  38.                 Log.e(TAG, "Exception while parsing '" + confFile.getAbsolutePath() + "'", e);  
  39.             } finally {  
  40.                 try { if (confreader != null) confreader.close(); } catch (IOException e) { }  
  41.             }  
  42.         }  
通过看代码大家可以发现,首先是将内部定义的apns.xml解析到数据库,然后是咱们自定义的一些apn(该文件存放在手机的/system/etc/apn-conf.xm)存入数据库;

2.4 系统设置--查询显示

 1)设置中查询显示在上面的操作过后咱们就有了一张叫做carriers的表,该表存放了所有的apn以及其相关的一些属性之类的;
 2)设置中的ApnSettings.java就是进入设置apn显示的界面,那该类怎么去加载属于自己的apn列表
      调用 fillList()方法填充这个列表,以下是该方法的核心代码:
    
[plain] view plaincopy
  1. private void fillList() {  
  2.     String where = "numeric=\""  
  3.             + getOperatorNumeric()  
  4.             + "\"";  
  5.     Cursor cursor = managedQuery(Telephony.Carriers.CONTENT_URI, new String[] {  
  6.             "_id", "name", "apn", "type"}, where,  
  7.             Telephony.Carriers.DEFAULT_SORT_ORDER);  
  8.   
  9.     PreferenceGroup apnList = (PreferenceGroup) findPreference("apn_list");  
  10.     apnList.removeAll();  
  11.   
  12.     ArrayList<Preference> mmsApnList = new ArrayList<Preference>();  
  13.   
  14.     mSelectedKey = getSelectedApnKey();  
  15.     cursor.moveToFirst();  
  16.     while (!cursor.isAfterLast()) {  
  17.         String name = cursor.getString(NAME_INDEX);  
  18.         String apn = cursor.getString(APN_INDEX);  
  19.         String key = cursor.getString(ID_INDEX);  
  20.         String type = cursor.getString(TYPES_INDEX);  
  21.   
  22.         ApnPreference pref = new ApnPreference(this);  
  23.   
  24.         if (name.contains("ro.")){  
  25.             //for china union  
  26.             if (ChinaUnionPLMN.equals(getOperatorNumeric())){  
  27.                 if (type.equals("default")){  
  28.                     if (name.contains("wap")){  
  29.                         name = getString(R.string.china_union_wap_apn_name);  
  30.                     }else{  
  31.                         name = getString(R.string.china_union_net_apn_name);  
  32.                     }  
  33.                 }  
  34.                 if (type.equals("mms")) name = getString(R.string.china_union_mms_apn_name);  
  35.                 if (type.equals("supl")) name = getString(R.string.china_union_supl_apn_name);  
  36.                 /**  
  37.                  * changed by zaokun,fix bug 12113,union apn can't edit  
  38.                  */  
  39.                // pref.setIsDefault(true);  
  40.             }  
  41.         }  
  42.   
  43.         pref.setKey(key);  
  44.         pref.setTitle(name);  
  45.         pref.setSummary(apn);  
  46.         pref.setPersistent(false);  
  47.         pref.setOnPreferenceChangeListener(this);  
  48.   
  49.         boolean selectable = ((type == null) || !type.equals("mms"));  
  50.         pref.setSelectable(selectable);  
  51.         if (selectable) {  
  52.             if ((mSelectedKey != null) && mSelectedKey.equals(key)) {  
  53.                 pref.setChecked();  
  54.             }  
  55.             apnList.addPreference(pref);  
  56.         } else {  
  57.             mmsApnList.add(pref);  
  58.         }  
  59.         cursor.moveToNext();  
  60.     }  
  61.     cursor.close();  
  62.   
  63.     for (Preference preference : mmsApnList) {  
  64.         apnList.addPreference(preference);  
  65.     }  
  66. }  
通过看代码发现方法的工作有三:
一、调用getOperatorNumeric()方法获取sim卡OperatorNumeric;以下是该方法的核心代码:

 
[plain] view plaincopy
  1. private String getOperatorNumeric() {  
  2.     String numeric;  
  3.     numeric = TelephonyManager.getTelephonyProperty  
  4.                 (TelephonyProperties.PROPERTY_ICC_OPERATOR_NUMERIC, mSubscription, "");  
  5.     if (TextUtils.isEmpty(numeric)) {  
  6.         numeric = TelephonyManager.getTelephonyProperty  
  7.                 (TelephonyProperties.PROPERTY_OPERATOR_NUMERIC, mSubscription, "");  
  8.     }  
  9.     return numeric;  
  10. }  
二、通过获取的OperatorNumeric查询数据库,其查询数据的操作,这里大家可以对照上面的代码即可;
三、ui显示
 

3、总结

     vpn的加载大致过程就是这样,其中可以看到最核心的是从两个xml里面加载apn数据到数据库,设置根据opratorNumber进行查询显示。当然这里的讲解不是很具体,如果大家希望对每个细节进行分析,可能还需要对每段代码仔细阅读。
原创粉丝点击