美文网首页Android开发
【通信篇4】APN模块总结

【通信篇4】APN模块总结

作者: 农民工Alan | 来源:发表于2020-08-31 19:48 被阅读0次

    1.APN简介

    APN(Access Point Name)是通过手机上网必须配置的一个参数,用来决定手机通过哪种接入方式来访问网络。只要我们的手机插上sim卡之后就可以在手机的设置中查看当前sim卡内置的默认apn参数,一般的安卓智能机都可以在sim卡设置中找到“接入点名称(APN)”并可以查看和新增apn。

    下面我们看看apn到底是怎么使用的,在启动Android手机或者启动Android虚拟设备后,所有的APN配置信息都会保存在telephony.db的SQLite数据库表名为carriers的表中。我们可以将此数据库文件pull到本地,然后可以查看carriers表的结构和其中的APN配置信息数据,命令如下:

    adb pull /data/user_de/0/com.android.providers.telephony
    如上可以将mmssms.db和telephony.db等数据都pull出来。
    在Android系统中APN配置文件的路径:
    1)vendor\qcom\proprietary\qrdplus\Extension\apps\etc\apns-config.xml
    2)framework\base\core\res\xml\apn.xm
    开机后,启动phone进程时,会加载运行在phone进程中的TelephonyProvider,TelephonyProvider负责解析apns-conf.xml文件,将其中定义的APN参数写入到数据库中。

    1.1 APN配置关键字段
    字段名称 描述
    name APN配置名称,如CMNET
    numeric 运营商编号,如46000
    mcc 移动国家码,如460
    mnc 移动网络码,如00
    apn APN接入点,比如中国移动有两个接入点:cmwap和cmnet
    user 用户名
    server 服务器地址
    password 密码
    proxy 代理服务器地址,如10.0.0.172
    port 端口号,如80
    mmsproxy 彩信代理服务器地址,如10.0.0.172
    mmsport 彩信代理服务器端口号,如80
    mmsc 彩信接入服务器地址,如http://mmsc.monternet.com
    type APN接入类型,如default,net,supl,xcap,不同类型用","分隔
    current
    protocol 连接该APN所用的协议,如IPV4IPV6
    roaming_protocol 漫游时连接该APN所用的协议,如IPV4IPV6
    carrier_enabled 用于标识APN是否可用
    bearer 无线接入,如LTE和eHRPD
    bearer_bitmask 无线接入技术位掩码,用于标明当前APN可以包含的RAT
    network_type_bitmask
    mvno_type 移动虚拟网络运营商(Mobile virtual network operator)的类型,可用的数据有spn,IMSI,GID(Group Identifier Level 1)
    mvno_match_data MVNO_TYPE数据,这个值是和MVNO_TYPE对应的。例如:SPN:A MOBILE,BEN NL,IMSI:302720x94,2060188 GID:4E,33
    sub_id 用于表明这个APN属于哪个subscription,此值从siminfo表获取
    profile_id Profile id,profile是modem侧存储信息的方式,这个值将APN和modem侧的profile联系起来
    modem_cognitive 用于表明这个APN是否会在modem侧设置
    max_conns APN支持的最大连接数量
    wait_time 使用该APN进行数据连接时,如果失败,retry要等待的时间
    max_conns_time 限制APN最大连接的时间
    mtu 使用该APN建立的连接,可以传输的最大单元
    edited 表明该APN是否被用户或运营商添加、编译或删除的状态
    user_visible APN是否对用户可见
    user_editable 用户是否可以编辑APN
    owned_by APN的拥有者,0或者1
    apn_set_id APN集合id,如果用户或者框架选择了一个apn作为首选APN,那么所有与选中apn相同集合id的APN拥有更高的优先级
    persistent
    read_only 是否只读
    ppp_number
    sourcetype
    csdnum
    ipversion
    1.2 Android支持的APN类型
    类型 描述
    default 默认数据连接、即浏览器、Email等手机上网数据连接
    mms 发送和接收彩信使用的数据连接
    supl 支持AGPS的数据连接
    dun(dial-up-network) 拨号连接
    hipri 扩展
    ims
    1.3 APN配置信息

    apn配置在apns-conf.xml中,carriers表中的数据和此文件中的数据内容一致,在加载TelephonyProvider的时候,会调用其initDatabase方法,将apns-conf.xml配置文件内容加载到carriers表中。

    2、APN设置

    2.1 重置APN

    1、在ApnSettings界面点击重置后,通过Uri: “content://telephony/carriers/restore"进行delete操作,删除完成后会重新fillList。
    2、进行delete操作时,TelephonyProvider通过URL_RESTOREAPN进行删除操作,会删除carriers表,同时删除首选APN,获取preferred-full-apn的SP,如果SP包含version1,表示apn已经存储起来了,删除该subId对应的version1字段以及APN唯一字段与subId组合在一起的字段,删除完成,重新初始化加载carrier表,
    3、在ApnSettings界面查询到APN后,会通过Uri:"content://telephony/carriers/
    preferapn" 去设置首选APN。

    初始化完成后,DcTracker监听到数据库变化执行onApnChanged,然后会设置偏好APN,此时会将oldApnSettings设置成首选APN,同时ApnSettings查询到APN list检测到如果没有偏好APN,会将第一个APN设置成偏好APN。APN如果配置了bearer_bitmask,且bearer_bitmask不为0,如果插入的卡网络类型识别的是unknown,查询出来的APN则会被过滤掉不显示。

    2.2切换APN

    1、在ApnSettings界面点击onPreferenceChange,执行setSelectedApnKey,设置首选APN
    通过URI:content://telephony/carriers/preferapn 和APN_ID为选中的id进行update。
    2、TelephonyProvider:获取subId,检查values中是否包含apn_id,如果包含apn_id,获取apn_id带过来的id值,将对应的apn_id保存为该subId的首选APN
    3、DcTracker:监听到数据库变化,ApnChangeObserver的onChange函数将被调用,触发onApnChange函数,onApnChange的时候,底层会清除掉所有的连接。

    2.3 新建APN

    1、ApnEditor:布局初始化,获取相关控件,获取subId等intent传过来的参数,插入一条仅有id的信息,并根据插入信息返回uri,根据uri查询相应id的数据。
    2、根据查询到的数据fillUi进行显示,如果是新建的,mvnoType显示有差异,mvnoMatchData显示有差异
    3、移动定制版本,APN协议和APN漫游协议默认为IpV4V6、设置SIM卡相关的监听、APN变化的TextWatcher
    4、在onResume中会注册phone状态、插拔卡等的监听
    5、(1)点击保存:内置的APN则弹框提示是否保存,非内置的APN,直接验证并保存,如果APN相关有用信息为空,则toast提示,不保存返回,根据各项字段,通过uri更新数据库中数据。

    2.4 编辑APN

    1、ApnEditor:布局初始化,获取相关控件,获取subId等intent传过来的参数,获取传递过来的uri,uri以id结尾,如果uri为空或不满足要求则返回,关闭界面。
    2、根据uri查询相应id的数据,根据查询到的数据fillUi进行显示,设置SIM卡相关的监听、APN变化的TextWatcher
    3、在onResume中会注册phone状态、插拔卡等的监听,如果配置了ReadOnly字段,则不可保存、不可编辑preferene项
    4、(1)点击保存:name、APN、mcc、mnc 四项不能为空,如果为空则返回不让保存,内置的APN则弹框提示是否保存,非内置的APN,直接验证并保存,如果APN相关有用信息为空,则toast提示,不保存返回,根据各项字段,通过uri更新数据库中数据。
    (2)修改mcc,点击保存,此时发生冲突时,更新旧的那条数据,然后删除掉要更新的这条数据,此时要更新这条APN就从数据库中删除了,此时不会触发onApnChange,不会导致DcTracker重新触发连接的逻辑。重启手机后,此时通过numeric查询APN是无法查到的,因为数据库中的那条APN的mnc和numeric已经相对应的被修改了。

    3 TelephonyProvider

    3.1 APN升级

    APN升级在TelephonyProvider中实现,先获取首选APN保存,然后根据条件删除数据库。重新根据xml插入APN,根据名称、APN、numeric、bearer四个属性恢复首选APN,若其中有属性变更,则不恢复。

    4、 APN流程

    4.1 卡加载后,监听APN数据库变化
    public DcTracker(Phone phone) {
        .......
        //每个Phone对象有自己DcTracker
        //每个DcTracker加载各自卡可用的APN
        mPhone = phone;
        .......
        //1、监听卡载入
        mUiccController = UiccController.getInstance();
        mUiccController.registerForIccChanged(this, DctConstants.EVENT_ICC_CHANGED, null);
        .......
        //2、监听卡信息变化
        mSubscriptionManager = SubscriptionManager.from(mPhone.getContext());
        mSubscriptionManager.addOnSubscriptionsChangedListener(mOnSubscriptionsChangedListener);
        .......
        //监听APN数据库变化
        mApnObserver = new ApnChangeObserver();
        phone.getContext().getContentResolver().registerContentObserver(
                Telephony.Carriers.CONTENT_URI, true, mApnObserver);
        .............
        //初始化不同APN类型对应的网络能力,后文介绍
        initApnContexts();
        .............
        // Add Emergency APN to APN setting list by default to support EPDN in sim absent cases
        initEmergencyApnSetting();
        addEmergencyApnSetting();
        ...............
    }
    

    4)插卡或卡发生变化后,就要创建当前卡可用的APN,同时设置初始时使用的APN

    private void onRecordsLoadedOrSubIdChanged() {
        ..............
        //1、创建当前卡可用的APN
        createAllApnList();
    
        //2、设置初始使用的APN
        setInitialAttachApn();
    
        if (mPhone.mCi.getRadioState().isOn()) {
            if (DBG) log("onRecordsLoadedOrSubIdChanged: notifying data availability");
            notifyOffApnsOfAvailability(Phone.REASON_SIM_LOADED);
        }
    
        //卡变化也会触发拨号流程;不过若此时数据开关未开,那么拨号是不会成功的
        setupDataOnConnectableApns(Phone.REASON_SIM_LOADED);
    }
    

    创建卡对应的APN的过程:

    private void createAllApnList() {
        //表示mvno是否匹配
        //mvno也是APN的一种属性,代表该APN适用于虚拟运营商,目前用的比较少
        mMvnoMatched = false;
    
        //用于保存结果
        mAllApnSettings = new ArrayList<ApnSetting>();
    
        //得到当前卡的信息
        IccRecords r = mIccRecords.get();
        //得到卡对应的MCC/MNC
        String operator = (r != null) ? r.getOperatorNumeric() : "";
        if (operator != null) {
            //构造SQL语句
            String selection = "numeric = '" + operator + "'";
            String orderBy = "_id";
            ...............
            //查询MCC/MNC对应的APN
            Cursor cursor = mPhone.getContext().getContentResolver().query(
                    Telephony.Carriers.CONTENT_URI, null, selection, null, orderBy);
    
            if (cursor != null) {
                if (cursor.getCount() > 0) {
                    //1、利用数据创建APN
                    mAllApnSettings = createApnList(cursor);
                }
                cursor.close();
            }
        }
    
        //2、添加emergencyApnSettings
        addEmergencyApnSetting();
    
        //3、去除重复的APN
        dedupeApnSettings();
    
        if (mAllApnSettings.isEmpty()) {
            mPreferredApn = null;
        } else {
            //4、得到用户偏爱的APN (用户在UI界面主动选择的)
            mPreferredApn = getPreferredApn();
            if (mPreferredApn != null && !mPreferredApn.numeric.equals(operator) {
                mPreferredApn = null;
                //用户偏爱的与当前卡不匹配,删除数据库中对应信息
                setPreferredApn(-1);
            }
        }
    
        //5、在需要的情况下,构造APN文件发送给modem
        setDataProfilesAsNeeded();
    }
    

    5.APN举例

    1)以中国移动举例:其中carrier、apn、mcc、mnc几个字段是一个完整的apn一定要有的,不同的卡mnc会存在不同的情况如,00、02,设置错误的情况下会无法上网。

    <apn carrier="China Mobile"
    apn=""
    mcc="460"
    mnc="00"
    type="ia"
    protocol="IPV4V6"
    roaming_protocol="IPV4V6"
    />
    <apn carrier="CMCC DM"
    apn=""
    mcc="460"
    mnc="00"
    type="fota"
    />
    <apn carrier="APN_NAME_CMNET"
    apn="cmnet"
    mcc="460"
    mnc="00"
    type="default,net,supl"
    preferred="true"
    protocol="IPV4V6"
    roaming_protocol="IPV4V6"
    />
    <apn carrier="APN_NAME_CMMMS"
    apn="cmwap"
    mcc="460"
    mnc="00"
    proxy="10.0.0.172"
    port="80"
    mmsproxy="10.0.0.172"
    mmsport="80"
    mmsc="http://mmsc.monternet.com"
    type="mms"
    protocol="IPV4V6"
    roaming_protocol="IPV4V6"
    />
    <apn carrier="APN_NAME_CMWAP"
    apn="cmwap"
    mcc="460"
    mnc="00"
    proxy="10.0.0.172"
    port="80"
    type="supl"
    protocol="IPV4V6"
    roaming_protocol="IPV4V6"
    />
    <apn carrier="China Mobile (IMS)"
    mcc="460"
    mnc="00"
    apn="ims"
    type="ims"
    protocol="IPV4V6"
    roaming_protocol="IPV4V6"
    profile_id="2"
    modem_cognitive="true"
    max_conns="1023"
    max_conns_time="300"
    />

    这里需要强调一下type和authtype,type字段可以有多个属性值,依次用逗号隔开,authtype在自己添加apn时可能给定的值是字符串,我们需要转换为相应的值。具体关系如下:

    属性值 合入值
    None 0
    不写(默认值) -1
    PAP 1
    CHAP 2
    PAP OR CHAP 3
    2)上网分为wap和net两种方式,使用net手机就会直接连入互联网,而使用wap则会中间多了一个代理网关,移动联通均是10.0.0.172,端口80。
    3)彩信APN

    彩信apn中mmsproxy和mmsport两个字段在发彩信的apn中是必须的

    6.Android支持的apn类型

    Android中支持的apn类型(”default, mms, supl, dun, hipri, fota, ims…….”),其功能如下所示:

    类型 描述
    default 默认数据连接,即浏览器、Email等普通连接(internet、wap、web)
    mms 接收和发送彩信使用的数据连接
    supl 支持APGS的数据连接(gprs上网)
    dun 拨号连接(wifi等上网类型,tethering)
    hipri 扩展

    此表中的数据优先级是由低到高的,即default数据连接的优先级最低,而hipri数据连接的优先级最高。比如在手机上网聊天时,将建立default数据连接;当手机收到一条彩信,因为彩信的数据连接是mms,这时会断开default数据连接而创建mms数据连接,从而能快速接收到此彩信,因为mms比default的数据连接优先级高。因此,在发送和接收彩信的同时不能上网。
    APN分类
    1、default

    默认网络连接,当激活时所有数据传输都使用该连接,不能与其他网络连接同时使用

    适用场合:绝大部分正常上网时可以使用

    2、mms

    彩信专用连接,此连接与default类似,用于与载体的多媒体信息服务器对话的应用程序,此连接能与default连接同时使用

    适用场合:使用彩信服务时,必须有mms类型的接入点,不必选中,应用程序会自动使用此接入点

    3、supl

    是SecureUser Plane Location“安全用户面定位”的简写,此连接与default类似,用于帮助定位设备与载体的安全用户面定位服务器对话的应用程序,此连接能与default连接同时使用

    4、dun

    Dial UpNetworking拨号网络的简称,此连接与default连接类似,用于执行一个拨号网络网桥,使载体能知道拨号网络流量的应用程序,此连接能与default连接同时使用

    适用场合:当我们使用自己的手机给别人做热点时使用,不管是USB 热点,wifi热点或则bluetooth热点。将他与default区别开来的主要目的一般是方面计费,国外很多运营商手机自己上网和做热点计费不同的。目前在国内三大运营商都没有区分,所以也就没有dun这个apn

    5、hipri

    高优先级网络,与default类似,但路由设置不同。使用较少。

    6、ims

    当ims发起激活请求时会使用这个apn连建立ims的专用承载.

    7、FOTA

    手机FOTA升级的时候使用

    8.IA

    IA的apn专用于LTE attach使用,在手机检测到sim卡后,便会加载这个attach apn. 不过很多运营商并没有严格规定attach apn,所以常常复用default类型的apn。 在attachapn 加载的时候它有一个优先级顺序,如下:

    IaApn > PreferredApn > DefaultApn>FirstApn

    IaApn : 类型为ia的apn,优先级最高。

     PreferredApn :选中的apn。比如在手机setting里面设置的那个apn
    
     DefaultApn :从apnlist里面查询到的第一个类型为“default”的apn
    
     FirstApn :apnlist中的第一个apn。
    

    APN加载和过滤
    在每次开机的时候系统回自动检查telephony.db是否存在,如果不存在则会创建数据库telephony.db,并利用apns-conf.xml中的内容生成表carriers,以后所有对apn的操作都会是直接针对表carriers,包括查询,创建,修改,删除等。

    当插入一张卡后系统会根据卡的相关信息来匹配相应的apn,在apn list中主要涉及匹配的项有:mcc,mnc,mvno_type, mvno_match_data。mvno_type值决定mvno_match_data的值,android原生代码里mvno_type会有4个值,他们分别是“spn”,“imsi”,“gid”, “iccid”。所以,在apn 读取的时候,会先根据sim卡的mcc,mnc读取出相应的apn list,接着会判断apn list 中的每一个apn的mvno_type 的值,如果不为空,则会根据mvno_type 和mvno_match_data再一次对apn list进行过滤,一般情况下,mvno_type,mvno_match_data为空。

    7、常见的APN问题

    7.1 重置APN,显示为默认的APN接入点后又变为手动更改的接入点
    D ApnSettings: --restoreDefaultApn--  ——开始重置
    D TelephonyProvider: restoreDefaultAPN: where: owned_by!=0
    
    D TelephonyProvider: deletePreferredApn: for subId 1
    D TelephonyProvider: deletePreferredApn: apn is stored. Deleting it now for subId 1
    D TelephonyProvider: dbh.initDatabase:+ db=SQLiteDatabase: /data/user_de/0/com.android.providers.telephony/databases/telephony.db ——重新创建
    D TelephonyProvider: dbh.initDatabase:- db=SQLiteDatabase: /data/user_de/0/com.android.providers.telephony/databases/telephony.db ——插入数据库完成
    D TelephonyProvider: setPreferredApn: _id 2965 subId 1 ————设置偏好APN
     DCT     : [ApnContext:default] getApnSetting: apnSetting=[ApnSettingV5] CUWAP, 2966, 46001, 3gwap, 10.0.0.172, http://mmsc.myuni.com.cn, 10.0.0.172, 80, 80, -1, default | mms, IPV4V6, IPV4V6, true, 0, 0, 0, false, 0, 0, 0, 0, , , false, 0, 0
     DCT     : [ApnContext:default] getApnSetting: apnSetting=[ApnSettingV5] CUWAP, 2966, 46001, 3gwap, 10.0.0.172, http://mmsc.myuni.com.cn, 10.0.0.172, 80, 80, -1, default | mms, IPV4V6, IPV4V6, true, 0, 0, 0, false, 0, 0, 0, 0, , , false, 0, 0
     QtiDCT  : [0]buildWaitingApns: reset preferred APN to [ApnSettingV5] CUWAP, 2966, 46001, 3gwap, 10.0.0.172, http://mmsc.myuni.com.cn, 10.0.0.172, 80, 80, -1, default | mms, IPV4V6, IPV4V6, true, 0, 0, 0, false, 0, 0, 0, 0, , , false, 0, 0 ——设置偏好APN失败,重置到2966了
    从log可知,上层设置2965 APN时未设置成功,底层重新设置了2966
    
    //上层设置偏好APN 2965
    Line 58117: 06-21 14:43:07.940  2883  3252 D TelephonyProvider: setPreferredApn: _id 2965 subId 1 
    //framework设置偏好APN 2966
    Line 4405: 06-21 14:43:07.939  2883  2883 D QtiDCT  : [0]buildWaitingApns: reset preferred APN to [ApnSettingV5] CUWAP, 2966, 46001, 3gwap, 10.0.0.172, http://mmsc.myuni.com.cn, 10.0.0.172, 80, 80, -1, default | mms, IPV4V6, IPV4V6, true, 0, 0, 0, false, 0, 0, 0, 0, , , false, 0, 0 ——设置偏好APN失败,重置到2966了
    //framerok调用删除
    Line 4406: 06-21 14:43:07.939  2883  2883 D QtiDCT  : [0]setPreferredApn: delete 
    //OS写入完成,数据库执行完打印的log
    Line 58119: 06-21 14:43:07.943  5337  5337 D _ApnSettings: set key to  2965
    //framework开始写入偏好APN
    Line 4407: 06-21 14:43:07.967  2883  2883 D QtiDCT  : [0]setPreferredApn: insert
    //响应framework的操作,写入偏好APN 2966
    Line 58161: 06-21 14:43:07.967  2883  2883 D TelephonyProvider: delete:match=12
    Line 58162: 06-21 14:43:07.967  2883  2883 D TelephonyProvider: subIdString = 1 subId = 1
    Line 58163: 06-21 14:43:07.967  2883  2883 D TelephonyProvider: deletePreferredApn: for subId 1
    Line 58164: 06-21 14:43:07.967  2883  2883 D TelephonyProvider: deletePreferredApn: apn is stored. Deleting it now for subId 1
    Line 58170: 06-21 14:43:07.972  2883  2883 D TelephonyProvider: subIdString = 1 subId = 1 ——此处log只有对应URL_PREFERAPN_NO_UPDATE_USING_SUBID 或者URL_PREFERAPN_USING_SUBID URI才会打印出来
    Line 58171: 06-21 14:43:07.973  2883  2883 D TelephonyProvider: setPreferredApn: _id 2966 subId 1
    //从上面流程可以看出,最后执行的是响应 framework的写入2966的操作
    

    分析:在buildWaitingAPN()中增加的reset preferred APN的逻辑和上层冲突,导致preferred APN值不对,这段已经不需要。上层在restore APN时会设置default preferred APN
    方案:删除reset prefered APN逻辑

    7.2 升级后,SIM2的APN需要重新选择

    分析:
    (1)从log来看,卡2没有选择默认的APN,故会弹框通知设置APN
    (2)对比升级前后的apn可知,升级后由于名称改变了,相当于APN变更了,故需要重新设置APN

    7.3 手动配置APN

    手动配置APN需要配置的元素,例如:
    (1)name:ims
    (2)APN:ims
    (3)type:ims
    (4)APN protocol & APN roaming protocol:IPV4V6

    相关文章

      网友评论

        本文标题:【通信篇4】APN模块总结

        本文链接:https://www.haomeiwen.com/subject/almfdftx.html