Bootstrap

Android V QCOM GPS | APN for LocationService

问题

在高通平台上验证 GPS 功能流程时候,block 在 APN 数据库的查询。经查,发现高通有内部实现的 LocationService(aosp源码和mtk都没有的类) 包含查询 TelephonyProvider 数据库的逻辑,直接原因是查询到 APN Protocol 不符合预期,直接fail。

关于 Android APN 数据列的更新,涉及的代码主要存在于 Android 的 Telephony Provider 数据库实现中。

先抛出本文关注的疑问:

  1. 什么时候会把数据库单行 APN 的 current 列置为1?
  2. 在 DataProfile 结构中是否会打印 current 信息?不会,看ApnSetting存的信息不包含current。

日志分析

// 用于数据建立的 APN 是正常的,按照插入卡的 MCCMNC+MVNO 完全匹配。

// 如下案例,Home Protocol 是仅 IPV6,Roaming 使用仅IPV4

12-18 02:49:23.140 D/DPM-0   ( 4432): Found 6 data profiles. profiles = [[DataProfile=[ApnSetting] T-Mobile US, 2062, 310260, fast.t-mobile.com, , http://mms.msg.eng.t-mobile.com/mms/wapenc, , null, null, 0, mms | supl | hipri | default | xcap | rcs, IPV6, IP, true, 0, false, 0, 0, 0, 1440, 1440, gid, 544D, false, GPRS|EDGE|UMTS|CDMA|CDMA - EvDo rev. 0|CDMA - EvDo rev. A|CDMA - 1xRTT|HSDPA|HSUPA|HSPA|iDEN|CDMA - EvDo rev. B|LTE|CDMA - eHRPD|HSPA+|GSM|TD_SCDMA|LTE_CA|NR, UNKNOWN, 0, -1, -1, false, 3, 961, false, UNEDITED, TrafficDescriptor={mDnn=fast.t-mobile.com, null}, preferred=false],

// 没查到protocol的时候默认是双栈(因为此时插卡后第一次开机,所有 APN 的 current 都没有被置为1,导致无法查询成功,所以什么时候将 APN 设置成 current?

12-18 02:52:56.719 D/LocSvc_java(10198): ipProtocol: null apn: fast.t-mobile.com networkType: LTE state: 1

12-18 02:52:56.719 W/LocSvc_java(10198): ipProtocol not found in db, default to ipv4v6

// 前后的Dataprofile都是正常的,同上

12-18 02:53:23.463 V/DPM-0   ( 4432): Satisfied profile: [DataProfile=[ApnSetting] T-Mobile US, 2062, 310260, fast.t-mobile.com, , http://mms.msg.eng.t-mobile.com/mms/wapenc, , null, null, 0, mms | supl | hipri | default | xcap | rcs, IPV6, IP, true, 0, false, 0, 0, 0, 1440, 1440, gid, 544D, false, GPRS|EDGE|UMTS|CDMA|CDMA - EvDo rev. 0|CDMA - EvDo rev. A|CDMA - 1xRTT|HSDPA|HSUPA|HSPA|iDEN|CDMA - EvDo rev. B|LTE|CDMA - eHRPD|HSPA+|GSM|TD_SCDMA|LTE_CA|NR, UNKNOWN, 0, -1, -1, false, 3, 961, false, UNEDITED, TrafficDescriptor={mDnn=fast.t-mobile.com, null}, preferred=true], last setup=02:49:23.348

// 同步核实 attach 网络正常

12-18 02:58:27.509 D/RILJ    ( 3502): [0634]> SET_INITIAL_ATTACH_APN[DataProfile=[ApnSetting] T-Mobile US, 2062, 310260, fast.t-mobile.com, , http://mms.msg.eng.t-mobile.com/mms/wapenc, , null, null, 0, mms | supl | hipri | default | xcap | rcs, IPV6, IP, true, 0, false, 0, 0, 0, 1440, 1440, gid, 544D, false, GPRS|EDGE|UMTS|CDMA|CDMA - EvDo rev. 0|CDMA - EvDo rev. A|CDMA - 1xRTT|HSDPA|HSUPA|HSPA|iDEN|CDMA - EvDo rev. B|LTE|CDMA - eHRPD|HSPA+|GSM|TD_SCDMA|LTE_CA|NR, UNKNOWN, 0, -1, -1, false, 3, 961, false, UNEDITED, TrafficDescriptor={mDnn=fast.t-mobile.com, null}, preferred=true] [PHONE0]

// AGPS查询到 APN 时, protocol 仍然是有问题的

12-18 02:58:45.445 D/LocSvc_java( 6627): ipProtocol: IPV4V6 apn: fast.t-mobile.com networkType: LTE state: 1
12-18 02:58:45.446 D/LocSvc_java( 6627): handleAgpsConnOpen mAgpsType: 1 mAPN: fast.t-mobile.com mBearerType: 3

代码分析

直接原因:核对代码是查询条件的差异。

AGPS查询激活的APN

定位服务没有按照卡和APN类型进行查询,而是通过apn值以及激活的APN匹配??

Cursor cursor = mContext.getContentResolver().query(Carriers.CONTENT_URI,
                                                new String[] {Carriers.PROTOCOL},
                                                selection, null,
                                                Carriers.DEFAULT_SORT_ORDER);

调用的形参是 Carriers 的 CONTENT_URI 是 TelephonyProvider 的定义,通用Google 数据库 "content://telephony/carriers"

    /**
     * Carriers class contains information about APNs, including MMSC information.
     */
    public static final class Carriers implements BaseColumns {
        /**
         * The {@code content://} style URL for this table.
         * For MSIM, this will return APNs for the default subscription
         * {@link SubscriptionManager#getDefaultSubscriptionId()}. To specify subId for MSIM,
         * use {@link Uri#withAppendedPath(Uri, String)} to append with subscription id.
         */
        @NonNull
        public static final Uri CONTENT_URI = Uri.parse("content://telephony/carriers");

    }

一开始认为是客制化 URI 的问题,但是更换了 URL 仍然查询有问题,根因还是筛选的行数据不准确。

TelephonyProvider 的数据库

在 data/user_de/0/com.android.providers.telephony/databases 的 telephony.db 中,APN 配置会加载到 carriers 表。

telephony.db carriers table
telephony.db carriers table

经过格式化的建表DDL SQL,包含49列(不是全部都会存在ApnSetting里面),UNIQUE 有28列,可见不是仅通过mccmnc+mvno 差分APN的。

CREATE TABLE carriers (
    _id INTEGER PRIMARY KEY,
    name TEXT DEFAULT '',
    numeric TEXT DEFAULT '',
    mcc TEXT DEFAULT '',
    mnc TEXT DEFAULT '',
    class TEXT DEFAULT '',
    apn_source INTEGER DEFAULT -1,
    modify_apn_name_id INTEGER DEFAULT -1,
    carrier_id INTEGER DEFAULT -1,
    apn TEXT DEFAULT '',
    user TEXT DEFAULT '',
    server TEXT DEFAULT '',
    password TEXT DEFAULT '',
    proxy TEXT DEFAULT '',
    port TEXT DEFAULT '',
    mmsproxy TEXT DEFAULT '',
    mmsport TEXT DEFAULT '',
    mmsc TEXT DEFAULT '',
    authtype INTEGER DEFAULT -1,
    type TEXT DEFAULT '',
    current INTEGER,
    sourcetype INTEGER DEFAULT 0,
    protocol TEXT DEFAULT 'IP',
    roaming_protocol TEXT DEFAULT 'IP',
    carrier_enabled BOOLEAN DEFAULT 1,
    bearer INTEGER DEFAULT 0,
    bearer_bitmask INTEGER DEFAULT 0,
    network_type_bitmask INTEGER DEFAULT 0,
    lingering_network_type_bitmask INTEGER DEFAULT 0,
    mvno_type TEXT DEFAULT '',
    mvno_match_data TEXT DEFAULT '',
    sub_id INTEGER DEFAULT -1,
    profile_id INTEGER DEFAULT 0,
    modem_cognitive BOOLEAN DEFAULT 0,
    max_conns INTEGER DEFAULT 0,
    wait_time INTEGER DEFAULT 0,
    max_conns_time INTEGER DEFAULT 0,
    mtu INTEGER DEFAULT 0,
    mtu_v4 INTEGER DEFAULT 0,
    mtu_v6 INTEGER DEFAULT 0,
    edited INTEGER DEFAULT 0,
    user_visible BOOLEAN DEFAULT 1,
    user_editable BOOLEAN DEFAULT 1,
    owned_by INTEGER DEFAULT 1,
    apn_set_id INTEGER DEFAULT 0,
    skip_464xlat INTEGER DEFAULT -1,
    always_on INTEGER DEFAULT 0,
    infrastructure_bitmask INTEGER DEFAULT 3,
    esim_bootstrap_provisioning BOOLEAN DEFAULT 0,
    UNIQUE (
        apn_set_id,
        mmsc,
        mmsport,
        numeric,
        mcc,
        carrier_enabled,
        carrier_id,
        protocol,
        bearer,
        mvno_type,
        infrastructure_bitmask,
        sourcetype,
        class,
        apn,
        user_editable,
        mnc,
        mvno_match_data,
        owned_by,
        network_type_bitmask,
        modify_apn_name_id,
        proxy,
        esim_bootstrap_provisioning,
        port,
        profile_id,
        roaming_protocol,
        name,
        apn_source,
        mmsproxy
    )
);

UNIQUE 是 SQL 中的一种约束条件,用于确保表中某一列或多列的值唯一。它可以防止在数据库表中插入重复的值,从而维护数据的完整性和一致性。

current=1表示正在活跃使用的APN,默认是null的。

telephony.db carriers table - current col
telephony.db carriers table - current col

current 激活案例

插入联通卡驻网,可见current会置为1.

Note:换卡可能不会更新db数据值,这是个问题。必现步骤,刷机插卡开机,能查看到TMO卡各种310-260 160+条被更新为current=1,为什么移动卡不会呢?

adb debug 查询

通过 adb 命令,在 debug 阶段可以方便数据数据

adb shell
# 查询激活的 “ims” APN
content query --uri content://telephony/carriers --where "current=1 AND apn='ims' AND carrier_enabled=1" --sort "name ASC"
# 按值查询APN
content query --uri content://telephony/carriers --where "apn='fast.t-mobile.com' AND carrier_enabled=1" --sort "name ASC"

DataProfile APN配置

在 DPM 中获取并打印ApnSetting信息,结构看ApnSetting builder的字段定义和实现赋值,由 makeApnSetting 查询数据库得到builder 信息。

01-06 19:54:12.753  4552  4552 V DPM-0   : Satisfied profile: [DataProfile=[ApnSetting] T-Mobile US, 2062, 310260, fast.t-mobile.com, , http://mms.msg.eng.t-mobile.com/mms/wapenc, , null, null, 0, mms | supl | hipri | default | xcap | rcs, IPV6, IP, true, 0, false, 0, 0, 0, 1440, 1440, gid, 544D, false, GPRS|EDGE|UMTS|CDMA|CDMA - EvDo rev. 0|CDMA - EvDo rev. A|CDMA - 1xRTT|HSDPA|HSUPA|HSPA|iDEN|CDMA - EvDo rev. B|LTE|CDMA - eHRPD|HSPA+|GSM|TD_SCDMA|LTE_CA|NR, UNKNOWN, 0, -1, -1, false, 3, 961, false, UNEDITED, TrafficDescriptor={mDnn=fast.t-mobile.com, null}, preferred=false], last setup=never

顺序

mEntryName。mId,

mCarrierEnabled, mProfileId, 

Note:没有current的值,说明驻网不会用到和修改。

ApnSetting 字段解析

ApnSetting 字段(按结构体字段)

参考值

toString顺序编号

备注

mEntryName

T-Mobile US

1

配置的carrier字段

mApnName

fast.t-mobile.com

4

实际入网用的APN值

mProxyAddress

5

mProxyPort

9

portToString(mProxyPort)

mMmsc

6
;