Platform:Android-7.1.1_r22
1 什么是APN APN的全称为Access Point Name,即“接入点名称”,它决定了手机可以访问哪些类型的外部网络。 例如:APN类型 可接入的网络(用途) default 数据网络(普通上网) mms MMS(彩信) APN配置中的字段 name:“APN配置”的名称,可随意指定,非APN名称。 apn:APN名称,由运营商指定,如cmnet、3gnet等 proxy:代理服务器IP地址 port:代理服务器端口 user:用户名 password:密码 server: mmsc:彩信中心地址 mmsProxy:彩信代理服务器IP地址 mmsPort:彩信代理服务器端口 mcc:移动国家码 mnc:移动网络码 authType:认证类型,PAP、CHAP、PAP/CHAP apnType:APN类型,如default、mms等 protocol:网络协议,IPV4、IPV6、IPV4/IPV6 roamingProtocol:漫游状态下的网络协议 carrierEnabled: bearerMulti: mvnoType: mvnoMatchData: 2 APN配置的加载 不同运营商都定义了不同的APN,但我们使用手机时,一般是不需要手动进行APN相关设置的,这是因为手机厂已经在手机中预置了运营商的APN配置,而手机就会根据SIM卡中的mccmnc来自动选择合适的APN。 APN的配置保存在apns.xml和apns-conf.xml中,手机开机时,会将其中的内容全部加载到数据库telephony.db的carriers表中。 device/generic/goldfish/data/etc/apns-conf.xml frameworks/base/core/res/res/xml/apns.xml AOSP中这个是为空的 <!-- If you edit this version, also edit the version in the partner-supplied apns-conf.xml configuration file --> <apns version="8"> </apns> TelephonyProvider.java private static class DatabaseHelper extends SQLiteOpenHelper { ...... public void onCreate(SQLiteDatabase db) { if (DBG) log("dbh.onCreate:+ db=" + db); createSimInfoTable(db);createCarriersTable(db, CARRIERS_TABLE); // 在数据库telephony.db中建立表carriersinitDatabase(db); // 加载数据到表carriers if (DBG) log("dbh.onCreate:- db=" + db); } ...... } 程序首先会从apns.xml中读取APN配置; 然后再从apns-conf.xml中读取,而且会使用以下三个文件中最新的文件: etc/apns-conf.xml telephony/apns-conf.xml misc/apns-conf.xml 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); // 首先从apns.xml中读取APN配置,哪个路径下的? int publicversion = -1; try { XmlUtils.beginDocument(parser, "apns"); publicversion = Integer.parseInt(parser.getAttributeValue(null, "version"));loadApns(db, parser); // 把读出来的APN配置保存到数据库 } catch (Exception e) { loge("Got exception while loading APN database." + e); } finally { parser.close(); }// 从apns-conf.xml读取APN配置 // Read external APNS data (partner-provided) XmlPullParser confparser = null; File confFile = getApnConfFile(); // 获取最新的apns-conf.xml 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()); }loadApns(db, confparser); // 把读出来的APN配置保存到数据库 } catch (FileNotFoundException e) { ...... } SIM卡加载后,会触发DcTracker.onRecordsLoadedOrSubIdChanged() → createAllApnList()。 private void createAllApnList() { mMvnoMatched = false; mAllApnSettings = new ArrayList<ApnSetting>(); IccRecords r = mIccRecords.get(); String operator = (r != null) ? r.getOperatorNumeric() : ""; // 获取mccmnc if (operator != null) { String selection = "numeric = '" + operator + "'"; String orderBy = "_id"; ......// 根据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 mAllApnSettings = createApnList(cursor); } cursor.close(); } } addEmergencyApnSetting(); dedupeApnSettings(); if (mAllApnSettings.isEmpty()) { ...... } 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(); } 3 PreferredApn 当APN配置加载到数据库后,Preferred APN仍然是没有的,进入APN设置菜单后我们可发现所有APN都未被选中。 而当建立数据连接时,程序会从数据库中选取所有可用的APN,待数据连接建立成功后,建立数据连接成功的APN将会被设置为Preferred APN。 当然,我们也可以进入APN设置菜单手动设置Preferred APN。 数据连接建立过程中会调用到DcTracker.buildWaitingApns(),当Preferred APN为空时,就会把所有可用的APN加入WaitingApn列表,然后再用这些APN去建立数据连接,一旦某个APN建立数据连接成功后,就会被设为Preferred APN。 private ArrayList<ApnSetting> buildWaitingApns(String requestedApnType, int radioTech) { ...... if (usePreferred) { mPreferredApn = getPreferredApn(); // 获取Preferred APN,结果为null } ...... if (usePreferred && mCanSetPreferApn && mPreferredApn != null && mPreferredApn.canHandleType(requestedApnType)) { ......// mPreferredApn为null,不会走到这里面 } if (mAllApnSettings != null) { if (DBG) log("buildWaitingApns: mAllApnSettings=" + mAllApnSettings);// 在mAllApnSettings中选取所有可用的APN for (ApnSetting apn : mAllApnSettings) { if (apn.canHandleType(requestedApnType)) { if (ServiceState.bitmaskHasTech(apn.bearerBitmask, radioTech)) { if (DBG) log("buildWaitingApns: adding apn=" + apn); apnList.add(apn); } else { ...... } ...... return apnList; } 数据连接建立成功后会调用DcTracker.onDataSetupComplete(),进而把当前建立数据连接的APN设置为Preferred APN。 Preferred APN是保存在TelephonyProvider的SharedPreferences中的。 private void onDataSetupComplete(AsyncResult ar) { ...... if (ar.exception == null) { DcAsyncChannel dcac = apnContext.getDcAc(); ...... if (dcac == null) { ...... } else { ...... // everything is setup if(TextUtils.equals(apnContext.getApnType(),PhoneConstants.APN_TYPE_DEFAULT)) { ...... if (mCanSetPreferApn && mPreferredApn == null) { if (DBG) log("onDataSetupComplete: PREFERRED APN is null"); mPreferredApn = apn; if (mPreferredApn != null) { setPreferredApn(mPreferredApn.id); // 设置Preferred APN } } ...... }