private void onRecordsLoaded() { mAutoAttachOnCreationConfig = mPhone.getContext().getResources().getBoolean(com.android.internal.R.bool.config_auto_attach_data_on_creation); //创建APN参数 createAllApnList(); setInitialAttachApn(); if (mPhone.mCi.getRadioState().isOn()) { notifyOffApnsOfAvailability(Phone.REASON_SIM_LOADED); } //尝试发起数据业务 setupDataOnConnectableApns(Phone.REASON_SIM_LOADED); }【当APN改变时】,将会触发onApnChanged():
private void onApnChanged() { DctConstants.State overallState = getOverallState(); boolean isDisconnected = (overallState == DctConstants.State.IDLE || overallState == DctConstants.State.FAILED); if (mPhone instanceof GSMPhone) { ((GSMPhone)mPhone).updateCurrentCarrierInProvider(); } //创建APN参数 createAllApnList(); setInitialAttachApn(); //清除旧的连接 cleanUpAllConnections(!isDisconnected, Phone.REASON_APN_CHANGED); //尝试发起数据业务 setupDataOnConnectableApns(Phone.REASON_APN_CHANGED); }从上面两个过程对比我们发现,他们都通过两个步骤进行APN的创建,分别是createAllApnList()和setInitialAttachApn(),他们的作用分别是创建APN和设置默认APN。
下面分别来介绍这个过程。
private void createAllApnList() { mAllApnSettings = new ArrayList<ApnSetting>(); IccRecords r = mIccRecords.get(); //获取该SIM的PLMN String operator = (r != null) ? r.getOperatorNumeric() : ""; if (operator != null) { String selection = "numeric = '" + operator + "'"; //查询当前SIM的APN数据库 Cursor cursor = mPhone.getContext().getContentResolver().query(Telephony.Carriers.CONTENT_URI, null, selection, null, null); if (cursor != null) { if (cursor.getCount() > 0) { //根据APN参数创建APN列表 mAllApnSettings = createApnList(cursor); } cursor.close(); } } //添加紧急APN addEmergencyApnSetting(); //合并类似的APN dedupeApnSettings(); if (mAllApnSettings.isEmpty()) { mPreferredApn = null; } else { //寻找prefer APN mPreferredApn = getPreferredApn(); if (mPreferredApn != null && !mPreferredApn.numeric.equals(operator)) { mPreferredApn = null; setPreferredApn(-1); } } setDataProfilesAsNeeded(); }这个方法主要经历了三个步骤:
private void dedupeApnSettings() { ArrayList<ApnSetting> resultApns = new ArrayList<ApnSetting>(); int i = 0; while (i < mAllApnSettings.size() - 1) { ApnSetting first = mAllApnSettings.get(i); ApnSetting second = null; int j = i + 1; while (j < mAllApnSettings.size()) { second = mAllApnSettings.get(j); if (apnsSimilar(first, second)) { ApnSetting newApn = mergeApns(first, second); mAllApnSettings.set(i, newApn); first = newApn; mAllApnSettings.remove(j); } else { j++; } } i++; } }这里就一个去重的算法问题,这个算法的原理就是,经过一个循环,可以找到某个参数所有相同的组合。
private ApnSetting getPreferredApn() { if (mAllApnSettings.isEmpty()) { return null; } Cursor cursor = mPhone.getContext().getContentResolver().query( PREFERAPN_NO_UPDATE_URI, new String[] { "_id", "name", "apn" }, null, null, Telephony.Carriers.DEFAULT_SORT_ORDER); if (cursor != null) { mCanSetPreferApn = true; } else { mCanSetPreferApn = false; } if (mCanSetPreferApn && cursor.getCount() > 0) { int pos; cursor.moveToFirst(); pos = cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers._ID)); for(ApnSetting p : mAllApnSettings) { log("getPreferredApn: apnSetting=" + p); if (p.id == pos && p.canHandleType(mRequestedApnType)) { log("getPreferredApn: X found apnSetting" + p); cursor.close(); return p; } } } if (cursor != null) { cursor.close(); } return null; }
从其获取途径可以看到,他的URI("content://telephony/carriers/preferapn_no_update")中多了"preferapn_no_update"的参数,这也是该APN的特殊之处。
protected void setInitialAttachApn() { ApnSetting iaApnSetting = null; ApnSetting defaultApnSetting = null; ApnSetting firstApnSetting = null; if (mAllApnSettings != null && !mAllApnSettings.isEmpty()) { firstApnSetting = mAllApnSettings.get(0); for (ApnSetting apn : mAllApnSettings) { if (ArrayUtils.contains(apn.types, PhoneConstants.APN_TYPE_IA) && apn.carrierEnabled) { iaApnSetting = apn; break; } else if ((defaultApnSetting == null) && (apn.canHandleType(PhoneConstants.APN_TYPE_DEFAULT))) { //找到类型是APN_TYPE_DEFAULT的APN参数作为默认attach用 log("setInitialApn: defaultApnSetting=" + apn); defaultApnSetting = apn; } } } ApnSetting initialAttachApnSetting = null; if (iaApnSetting != null) { initialAttachApnSetting = iaApnSetting; } else if (mPreferredApn != null) { initialAttachApnSetting = mPreferredApn; } else if (defaultApnSetting != null) { initialAttachApnSetting = defaultApnSetting; } else if (firstApnSetting != null) { initialAttachApnSetting = firstApnSetting; } if (initialAttachApnSetting == null) { } else { //设置Attach用的APN参数 mPhone.mCi.setInitialAttachApn(initialAttachApnSetting.apn, initialAttachApnSetting.protocol, initialAttachApnSetting.authType, initialAttachApnSetting.user, initialAttachApnSetting.password, null); } }在上面这个过程中,遍历当前所有的APN列表,寻找类型是APN_TYPE_DEFAULT的APN,然后将该APN参数传递给Modem用于初始的Attach。