APN设置 --- 之一

5.2 设置默认APN

Phone进程中的DcTracker构造方法如下,

1,调用父类DcTrackerBase的构造方法,

super(p);

DcTrackerBase的构造方法主要逻辑如下,

监听SIM卡的变化,

mUiccController = UiccController.getInstance();
mUiccController.registerForIccChanged(this, DctConstants.EVENT_ICC_CHANGED, null);

也就是说,如果SIM卡有变化, UiccController会向DcTrackerBase发送EVENT_ICC_CHANGED消息, 

DcTrackerBase的handleMessage方法对该消息处理如下,

case DctConstants.EVENT_ICC_CHANGED: {
    onUpdateIcc();
    break;
}

会回调DcTracker的onUpdateIcc方法。

2,注册telephony.db数据库的变化,

mApnObserver = new ApnChangeObserver();
p.getContext().getContentResolver().registerContentObserver(
   Telephony.Carriers.CONTENT_URI, true, mApnObserver);

ApnChangeObserver是DcTracker的内部类,定义如下,

private class ApnChangeObserver extends ContentObserver {
     public ApnChangeObserver () {
          super(mDataConnectionTracker);
     }

     @Override
     public void onChange(boolean selfChange) {
         sendMessage(obtainMessage(DctConstants.EVENT_APN_CHANGED));
     }
}

而DcTrackerBase继承Handler,如下,

public abstract class DcTrackerBase extends Handler {

因此,一旦telephony.db数据库发生变化,会调用ApnChangeObserver 的onChange方法,然后调用Handler 

的sendMessage方法发送EVENT_APN_CHANGED消息。DcTracker的handleMessage方法对该消息处理如下,

case DctConstants.EVENT_APN_CHANGED:
    onApnChanged();
    break;

因此, 一旦telephony.db数据库发生变化,就会调用DcTracker的onApnChanged方法。

3, 调用initApnContexts方法初始化不同APN类型对应的网络,

initApnContexts();

4,其他

for (ApnContext apnContext : mApnContexts.values()) {
  // Register the reconnect and restart actions.
  IntentFilter filter = new IntentFilter();
  filter.addAction(INTENT_RECONNECT_ALARM + '.' + apnContext.getApnType());
  filter.addAction(INTENT_RESTART_TRYSETUP_ALARM + '.' + apnContext.getApnType());
  mPhone.getContext().registerReceiver(mIntentReceiver, filter, null, mPhone);
}
// Add Emergency APN to APN setting list by default to support EPDN in sim absent cases
initEmergencyApnSetting();
addEmergencyApnSetting();

这个章节论述onUpdateIcc方法设置默认APN流程,下个章节分析onApnChanged方法流程。

DcTracker的onUpdateIcc方法主要逻辑如下,

调用IccRecords的registerForRecordsLoaded方法进行注册,监听卡信息是否载入完成

if (newIccRecords != null) {
    if (mPhone.getSubId() >= 0) {
         log("New records found.");
         mIccRecords.set(newIccRecords);
         newIccRecords.registerForRecordsLoaded(
                            this, DctConstants.EVENT_RECORDS_LOADED, null);
         }
     } else {
         onSimNotReady();//SIM卡还未读出
}

如果SIM卡信息载入完成,则IccRecords会向DcTracker发送EVENT_RECORDS_LOADED,

 DcTracker的handleMessage对该消息处理如下,

case DctConstants.EVENT_RECORDS_LOADED:
    onRecordsLoaded();
    break;

DcTracker的onRecordsLoaded方法主要逻辑如下,

1,调用createAllApnList方法创建当前SIM卡的APN,

createAllApnList(); 

2,调用setInitialAttachApn方法设置初始使用的APN,

setInitialAttachApn();

3,调用setupDataOnConnectableApns方法发起拨号请求,

setupDataOnConnectableApns(Phone.REASON_SIM_LOADED);

当然, setupDataOnConnectableApns 方法也是通过调用trySetupData方法进行拨号的。

如果当前SIM卡未打开数据业务,则不会拨号成功。下面三个小节分别论述这三个方法。

2.1 createAllApnList

DcTracker的createAllApnList方法调用流程图如下,


createAllApnList方法主要逻辑如下,

1,在telephony.db数据库的carriers表单中查询当前SIM卡对应的APN信息,

并调用createApnList方法构造ApnSetting对象。如此,一般一个APN对应一个ApnSetting对象,

这样就完成了数据库中APN到ApnSetting对象的映射。

Cursor cursor = mPhone.getContext().getContentResolver().query(
       Telephony.Carriers.CONTENT_URI, null, selection, null, orderBy);
if (cursor != null) {
    if (cursor.getCount() > 0) {
        mAllApnSettings = createApnList(cursor, mIccRecords.get());
    }
    cursor.close();
}

2,添加emergencyApnSettings并删除重复的APN,

addEmergencyApnSetting();
        dedupeApnSettings();

3,调用getPreferredApn方法从telephony.db数据库的siminfo表中读出默认的APN,一般第一次为空,如果该APN和

当前卡的APN不匹配,则调用setPreferredApn方法删除telephony.db数据库的siminfo表中APN信息,

mPreferredApn = getPreferredApn(mAllApnSettings);
if (mPreferredApn != null && !mPreferredApn.numeric.equals(operator)) {
     mPreferredApn = null;
     setPreferredApn(-1);
}

setPreferredApn方法如下,

String subId = Long.toString(mPhone.getSubId());
Uri uri = Uri.withAppendedPath(PREFERAPN_NO_UPDATE_URI_USING_SUBID, subId);
log("setPreferredApn: delete");
ContentResolver resolver = mPhone.getContext().getContentResolver();
resolver.delete(uri, null, null); //首先调用delete方法删除

if (pos >= 0) { //当前pos为 -1,因此后面的insert方法不执行。
    log("setPreferredApn: insert");
    ContentValues values = new ContentValues();
    values.put(APN_ID, pos);
    resolver.insert(uri, values); //插入默认的APN信息
}

createAllApnList方法如下,

if (cursor.moveToFirst()) {
   do {
      ApnSetting apn = makeApnSetting(cursor);
      •••
if (apn.hasMvnoParams()) {
          if (r != null && ApnSetting.mvnoMatches(r, apn.mvnoType, apn.mvnoMatchData)) {
               mvnoApns.add(apn);//虚拟运营商
           }
       } else {
            mnoApns.add(apn); //运营商
       }
} while (cursor.moveToNext());

利用cursor对象循环调用makeApnSetting方法构造ApnSetting对象,

makeApnSetting方法就是利用cursor在telephony.db数据库的carriers表单中获取SIM卡对应的APN信息,

然后利用APN信息构造一个ApnSetting对象, makeApnSetting方法的部分代码如下,

String[] types = parseTypes(
cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.TYPE)));
ApnSetting apn = new ApnSetting(
                cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers._ID)),
•••

ApnSetting 是一个比较轻量级的类,主要包含APN的信息,以及相关解析APN信息的方法。

parseTypes方法如下,

String[] result;
// If unset, set to DEFAULT.
if (types == null || types.equals("")) {
    result = new String[1];
    result[0] = PhoneConstants.APN_TYPE_ALL;
} else {
   result = types.split(",");
}
return result;

这段代码是解析APN的type字段。APN的type域,决定了它提供的网络能力。

telephony.db数据库的carriers表单部分APN的type域如下,


APN type包含default时,利用这个APN建立的网络就具有Mobile能力,即能够用数据网络访问Internet;

 当APN type包含mms时,利用这个APN建立的网络就具有发送彩信的能力。从parseTypes函数可以看出,

当APN的type为空时,即没有配置时,APN的type被定义为APN_TYPE_ALL。 利用APN_TYPE_ALL建立的网络,将具有全部的网络能力。

正常情况下,这种设计是合理的:

运营商会不同的服务定义不同的网络,于是通过APN的type域进行区分;

但是,有的运营商在某些地区会用同一个网络支持所有的功能(例如在非洲的一些国家),此时将APN的type域写成

”default, mms, supl, dun, hipri, fota, ims…….”是件繁琐的事,

于是,就规定APN的type域为”“时,可以支持所有网络能力。然而,这种设计成为了Android的一个漏洞,在某些场景下,

将带来数据连接无法断开的问题。

到此,已经在telephony.db数据库中查询到了SIM卡对应的APN信息,并且构造出了对应的ApnSetting对象。这些对象最终

保存在DcTrackerBase的mAllApnSettings变量中,定义如下,

protected ArrayList<ApnSetting> mAllApnSettings = null;

以后很多地方都会使用到mAllApnSettings变量,例如拨号上网。

并且默认APN信息保存在mPreferredApn变量中,定义如下,

protected ApnSetting mPreferredApn = null;
  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值