BT_蓝牙电话本数据包分析

基于Android P版本分析

协议简述

蓝牙电话应用不但需要HFP协议来支持打电话的功能,同时在很多车载蓝牙应用中,都支持查看通讯录和通话记录等信息,而这一部分的所涉及到的协议为PBAP;

PBAP

PBAP:(Phone Book Access Profile)电话本访问协议,是一种基于OBEX的上层协议,该协议可以同步手机这些具有电话本功能设备上的通讯录和通话记录等信息;

OBEX

Object Exchange,对象交换协议,来源与红外通讯协议,但又不局限与具体的传输方式,后来被蓝牙组织SIG吸纳其中部分并进行优化处理作为蓝牙协议中的OBEX层用于蓝牙设备间的文件数据传输,如蓝牙传输文件(OPP)、同步电话簿(PBAP)和同步短信(MAP)等场景下都是以OBEX协议组织相关数据进行传输的;

OBEX协议有两种角色:Server和Client,通过request-response(请求-响应)形式进行交互,即客户端Client进行请求,服务端Server响应客户端请求的方式传输数据对象;

应用于PBAP协议中,Client只能进行数据的读取操作,不能对源数据进行修改,保证了源数据的安全性;

PBAP协议栈

PBAP应用层协议处于最上层,之后就是数据格式处理方式,由于通讯录在手机中都是以vCard的格式存储的,所以这边为vCard的数据处理格式。在往下就是通过OBEX协议层联通蓝牙协议栈中的RFCOMM,最后通过统一的数据传输通道L2CAP链路发送数据;

vCard格式
makefile 复制代码
BEGIN:VCARD\r\n
VERSION:3.0\r\n
N:;胡x;;;\r\n
FN:胡x\r\n
TEL;TYPE=CELL:610xxx\r\n
END:VCARD\r\n
  • BEGIN:VCARD:一组联系人信息开始标志
  • END:VCARD:结束标志
  • VERSION:版本
  • FN:姓名
  • TEL;TYPE=CELL:联系人联系方式

上述的参数为必要的,有些参数是可选项,例如:住址、邮件等信息;

当前vCard的版本有vCard 2.1 和 vCard 3.0 两个版本,所以PSE需要两种数据格式都支持,同步数据时根据PCE请求的哪种格式就以哪种格式封装数据进行传输。但是无论是哪种格式,vCard属性内容字符集使用唯一的字符编码utf-8格式进行编码转换;

协议栈中定义了两种角色:

  • PSE:Phone Book Server Equipment,拥有电话本源数据的设备,作为Server,比如手机;
  • PCE:Phone Book Client Equipment,向PSE端请求电话本源数据的设备,作为Client,例如车机;

因为PBAP协议是基于OBEX协议实现的,那PBAP协议获取数据的方式也是通过request-response形式传输的;

PSE & PCE 功能
Feature Support by the PCE Support by the PSE
Download C1 M
Browsing C1 M
Database Identifier C3 M
Folder Version Counters O M
vCard Selecting O M
Enhanced Missed Calls O O
X-BT-UCI vCard Property O O
X-BT-UID vCard Property O O
Referencing Contacts C2 C2
Contact Image Default Format X M
  • C1:至少支持其中一种
  • C2:如果支持' X-BT-UID vCard Property ',则可选,否则不支持不可选
  • C3:如果支持"Folder Version Counters" 或 "X-BT-UID vCard Property",则必选,否则可选
  • O:可选
  • M:必选,必须支持

我们常使用到的功能为:Download和Browsing;我们分析一下;

Download

Download功能可以将电话簿对象的全部内容同步到PCE,从而PCE端获取到数据后完全可以通过蓝牙电话等应用程序将数据显示到界面,一样可以达到滚动浏览电话簿信息的目的;

Download这个功能特别是用于PSE端存储的电话簿容量相对较大,PCE设备通常从PSE端下载这些大容量数据并在其本地存储整个电话簿的场景。

Feature Function Support by the PCE Support by the PSE
Phone Book Download feature PullPhonebook M M

协议层提供了PullPhonebook函数,这个函数就是用来下载自己感兴趣的电话簿对象;

PullPhonebook Data Format

由于PBAP协议是基于OBEX的,所以PullPhonebook函数顾名思义也是采用request-response这种一问一答的形式传输数据;

请求格式如下:

Field / Header Name Value Status
Field Opcode GET(0x03 or 0x83) M
Field Packet Length Varies M
Header Connection ID Varies M
Header Single Response Mode 0x01 C1
Header Single Response Mode Param 0x01 C2
Header Name Object name (*.vcf) M
Header Type "x-bt/phonebook" M
Header Application Parameters
- PropertySelector Varies O
- Format Varies O
- MaxListCount Varies O
- ListStartOffset Varies O
- ResetNewMissedCalls Varies C3
- vCardSelector Varies C4
- vCardSelectorOperator Varies C5
  • Opcode:操作码,可以理解为标识码,和Type参数组合形成了唯一标识;
  • Connection ID:PBAP连接指令中PSE回复的连接ID 号;
  • Name:表明了需要同步哪种数据;
  • Type:对应了Function,基本上每一个Function对应一个Type,除了SetPhonebook Function;
  • Application Parameters:应用设置的参数,PSE的回复数据会根据这些参数来组装回复data数据,其中就包括了PropertySelector、Format、MaxListCount等参数信息;
  • MaxListCount:本次 GET 获取的最大List Count;
  • ListStartOffset:本次 GET 开始的List Offset;

响应格式如下:

Field / Header Name Value Status
Field Response 0x09 or 0xA0 or Error Code M
Field Packet Length Varies M
Header Single Response Mode 0x01 C1
Header Single Response Mode Param 0x01 C2
Header Application Parameters
- PhonebookSize Varies C3
- NewMissedCalls Varies C4
- PrimaryFolderVersion Varies C5
- SecondaryFolderVersion Varies C5
- DatabaseIdentifier Varies C6
Header Body/End of Body vCard object(s) C7
  • PhonebookSize:Name个数,当MaxListCount = 0时,返回Name的总个数;
  • NewMissedCalls:新增的未接电话
  • Body/End or Body:请求中MaxListCount != 0时,返回Name对应的数据,回复数据中的vCard对象只应包含使用属性选择器Attribute Selector参数指示的属性,并且应使用格式Format参数指示的格式组装数据;
Application Parameters Header

该数据是由一组不同的TAG组成的整体的Application Parameters;

Value Tag ID Length Possible Values
Order 0x01 1 byte 0x00 = indexed 0x01 = alphanumeric 0x02 = phonetic
Search Value 0x02 variable Text
SearchProperty 0x03 1 byte 0x00 = Name 0x01 = Number 0x02 = Sound
MaxListCount 0x04 2 bytes 0x0000 to 0xFFFF
ListStartOffset 0x05 2 bytes 0x0000 to 0xFFFF
PropertySelector 0x06 8 bytes 64 bits mask
Format 0x07 1 byte 0x00 = 2.1 0x01 = 3.0
PhonebookSize 0x08 2 bytes 0x0000 to 0xFFFF
NewMissedCalls 0x09 1 byte 0x00 to 0xFF
PrimaryVersionCounter 0x0A 16 bytes 0 to (2 128 -- 1)
SecondaryVersionCounter 0x0B 16 bytes 0 to (2 128 -- 1)
vCardSelector 0x0C 8 bytes 64 bits mask
DatabaseIdentifier 0x0D 16 bytes 0 to (2 128 -- 1)
vCardSelectorOperator 0x0E 1 byte 0x00 = OR 0x01 = AND
ResetNewMissedCalls 0x0F 1 byte 0x01 = Reset
PbapSupportedFeatures 0x10 4 bytes Bit 0 = Download Bit 1 = Browsing Bit 2 = Database Identifier Bit 3 = Folder Version Counters Bit 4 = vCard Selecting Bit 5 = Enhanced Missed Calls Bit 6 = X-BT-UCI vCard Property Bit 7 = X-BT-UID vCard Property Bit 8 = Contact Referencing Bit 9 = Default Contact Image Format Bit 10 ~ 31 Reserved 1
  • PropertySelector:用于指示请求的vCard object中应该包含的属性,PSE根据这些属性来组织恢复的Body/End of Body Header中包含的数据,PCE只能使用此Header接收所请求的vCard所需要内容,PSE不得回复任何其他性能数据,除非PCE有其他要求;

PropertySelector的值是由一个64位的数据组成,所以每一位都代表了一种属性,如果PCE请求的电话簿需要包含对应的数据,就将该数据对应在PropertySelector的二进制位设置为true(1)。具体每一位的含义见下图:

流程图

这里有一个需要注意的,PCE和PSE的服务连接不是一直保持的,只有在同步Phone Book的时候,服务保持连接,同步完成之后,就会断开;

Browsing

Feature Function Support by the PCE Support by the PSE
Phone Book Browsing Feature SetPhonebook M M
PullvCardListing M M
PullvCardEntry M M

  • SetPhonebook:选择感兴趣的Phone Object
  • PullvCardListing:client使用该Function获取感兴趣的Phone Object 列表
  • PullvCardEntry:client使用该Function获取感兴趣的Phone Object(单个)
SetPhonebook Data Format

请求格式:

Field / Header Name Value Status
Field Opcode SETPATH (0x05) M
Field Packet Length Varies M
Field Flags Up / Down / Root M
Field Constant Reserved (0) M
Header Connection ID Varies M
Header Name Name of the folder O

响应格式:

Field / Header Name Value Status
Field Response Code 0xA0 or Error Code M
Field Packet Length 3 M
PullvCardListing Data Format

请求格式:

Field / Header Name Value Status
Field Opcode GET(0x03 or 0x83) M
Field Packet Length Varies M
Header Connection ID Varies M
Header Single Response Mode 0x01 C1
Header Single Response Mode Param 0x01 C2
Header Name Name of the folder M
Header Type "x-bt/vcard-listing" M
Header Application Parameters
- Order Varies O
- SearchValue Varies O
- SearchProperty Varies C3
- MaxListCount Varies O
- ListStartOffset Varies O
- ResetNewMissedCalls Varies C4
- vCardSelector Varies C5
- vCardSelectorOperator Varies C6

响应格式:

Field / Header Name Value Status
Field Response Code 0x09 or 0xA0 or Error Code M
Field Packet Length Varies M
Header Single Response Mode 0x01 C1
Header Single Response Mode Param 0x01 C2
Header Application Parameters
- PhonebookSize Varies C3
- NewMissedCalls Varies C4
- PrimaryFolderVersion Varies C5
- SecondaryFolderVersion Varies C5
- DatabaseIdentifier Varies C6
Header Body/End of Body vCard object(s) C7
PullvCardEntry Data Format

请求格式:

Field / Header Name Value Status
Field Opcode GET(0x03 or 0x83) M
Field Packet Length Varies M
Header Connection ID Varies M
Header Single Response Mode 0x01 C1
Header Single Response Mode Param 0x01 C2
Header Name Object name (*.vcf) or X-BT-UID (X-BT-UID) M
Header Type "x-bt/vcard" M
Header Application Parameters
- PropertySelector Varies O
- Format Varies O

响应格式:

Field / Header Name Value Status
Field Response Code 0x09 or 0xA0 or Error Code M
Field Packet Length Varies M
Header Single Response Mode 0x01 C1
Header Single Response Mode Param 0x01 C2
Header Application Parameters
- DatabaseIdentifier Varies C3
Header Body/End of Body vCard object C4
流程图

vcf文件

Download和Browsing功能描述完成之后,我们需要知道,所有的Phone Object信息都是来自于PSE端,而在PSE端保存Phone Object的方式或者是路径可能有很多;

  • 存储设备

    • 手机:telecom/xxx.vcf
    • SIM卡:SIM1/telecom/xxx.vcf

无论是哪种存储方式,其对应都有相同的数据存储类型,例如通讯录、通讯记录,而在通讯记录中,又可以分为:来电、去电、未接来电、所有通讯记录。同时电话簿还提供了两个功能:快速拨号和收藏联系人;

上述描述的分类方式,对应了PSE端存储文件格式;

Phone Object AS Format Desc
Phone Book Object pb pb.vcf 通讯录
Incoming Calls History Object ich ich.vcf 来电通话记录
Outgoing Calls History Object och och.vcf 去电通话记录
Missed Calls History Object mch mch.vcf 未接来电通话记录
Commbined Calls History Object cch cch.vcf 所有的通话记录
Speed-Dial Object spd spd.vcf 快速拨号
Favorite Contacts Object fav fav.vcf 收藏通讯录

协议数据包分析

在PBAP协议同步通讯录和通讯记录中,都是基于OBEX协议实现的,PBAP协议作为了应用层协议;

同步通讯录

获取联系人数量 - telecom

Request:

yaml 复制代码
Frame 485: 84 bytes on wire (672 bits), 84 bytes captured (672 bits)
..............................
OBEX Protocol
    [Profile: PBAP (4)]
    [Current Path: /]
    .000 0011 = Opcode: Get (0x03)
    1... .... = Final Flag: True
    Packet Length: 70
    [Response in Frame: 489]
    Headers
        Connection Id: 1
            Header Id: Connection Id (0xcb)
                11.. .... = Encoding: 4 byte quantity (network order) (0x3)
                ..00 1011 = Meaning: Connection Id (0x0b)
            Connection ID: 1
        Name: "telecom/pb.vcf"
            Header Id: Name (0x01)
                00.. .... = Encoding: Null terminated Unicode text, length prefixed with 2 byte Unsigned Integer (0x0)
                ..00 0001 = Meaning: Name (0x01)
            Length: 33
            Name: telecom/pb.vcf
        Type: "x-bt/vcard-listing"
            Header Id: Type (0x42)
                01.. .... = Encoding: Byte sequence, length prefixed with 2 byte Unsigned Integer (0x1)
                ..00 0010 = Meaning: Type (0x02)
            Length: 22
            Type: x-bt/vcard-listing
        Application Parameters
            Header Id: Application Parameters (0x4c)
                01.. .... = Encoding: Byte sequence, length prefixed with 2 byte Unsigned Integer (0x1)
                ..00 1100 = Meaning: Application Parameters (0x0c)
            Length: 7
            Parameter: Max List Count
                Parameter Id: Max List Count (0x04)
                Parameter Length: 2
                Max List Count: 0 (0x0000)
  • Profile:PBAP (4),上层应用层协议为PBAP,OBEX协议的上层应用层协议除了PBAP,还有OPP、MAP协议;

  • Opcode:操作码,Get (0x03),即Request对应的code为Get;

  • Packet Length:70

  • Response in Frame:该request frame-485对应的Response frame为489;

  • Header - Connection Id = 1:PBAP连接指令中PSE回复的连接ID 号;

  • Header - Name = "telecom/pb.vcf":代表了访问的通讯录路径;

  • Header - Type = "x-bt/vcard-listing":代表了该Request对应的Function为PullvCardListing;

  • Header - Application Parameters

    • Parameter Id = 0x04:该ID 对应了Max List Count
    • Parameter - Max List Count = 0:在MaxListCount = 0 的情况下,Response返回的PhonebookSize为Name对应路径下所有通讯人的Count;

Response:

yaml 复制代码
Frame 489: 29 bytes on wire (232 bits), 29 bytes captured (232 bits)
....................................
OBEX Protocol
    [Profile: PBAP (4)]
    [Current Path: /]
    .010 0000 = Response Code: Success (0x20)
    1... .... = Final Flag: True
    Packet Length: 15
    [Request in Frame: 485]
    Headers
        Connection Id: 1
            Header Id: Connection Id (0xcb)
                11.. .... = Encoding: 4 byte quantity (network order) (0x3)
                ..00 1011 = Meaning: Connection Id (0x0b)
            Connection ID: 1
        Application Parameters
            Header Id: Application Parameters (0x4c)
                01.. .... = Encoding: Byte sequence, length prefixed with 2 byte Unsigned Integer (0x1)
                ..00 1100 = Meaning: Application Parameters (0x0c)
            Length: 7
            Parameter: Phonebook Size
                Parameter Id: Phonebook Size (0x08)
                Parameter Length: 2
                Phonebook Size: 102 (0x0066)
  • Response Code:Success

  • Header - Connection Id = 1:对应了上述Request 的Connection Id;

  • Header - Application Parameters

    • Parameter Id = 0x08:该Id代表了Phonebook Size
    • Parameter - Phonebook Size = 102:代表了Name对应telecom/pb.vcf的总数
获取联系人数量 - SIM1/telecom

Request:

yaml 复制代码
OBEX Protocol
    [Profile: PBAP (4)]
    [Current Path: /]
    .000 0011 = Opcode: Get (0x03)
    1... .... = Final Flag: True
    Packet Length: 80
    [Response in Frame: 492]
    Headers
        Connection Id: 1
            Header Id: Connection Id (0xcb)
                11.. .... = Encoding: 4 byte quantity (network order) (0x3)
                ..00 1011 = Meaning: Connection Id (0x0b)
            Connection ID: 1
        Name: "SIM1/telecom/pb.vcf"
            Header Id: Name (0x01)
                00.. .... = Encoding: Null terminated Unicode text, length prefixed with 2 byte Unsigned Integer (0x0)
                ..00 0001 = Meaning: Name (0x01)
            Length: 43
            Name: SIM1/telecom/pb.vcf
        Type: "x-bt/vcard-listing"
            Header Id: Type (0x42)
                01.. .... = Encoding: Byte sequence, length prefixed with 2 byte Unsigned Integer (0x1)
                ..00 0010 = Meaning: Type (0x02)
            Length: 22
            Type: x-bt/vcard-listing
        Application Parameters
            Header Id: Application Parameters (0x4c)
                01.. .... = Encoding: Byte sequence, length prefixed with 2 byte Unsigned Integer (0x1)
                ..00 1100 = Meaning: Application Parameters (0x0c)
            Length: 7
            Parameter: Max List Count
                Parameter Id: Max List Count (0x04)
                Parameter Length: 2
                Max List Count: 0 (0x0000)
  • Header - Name = "SIM1/telecom/pb.vcf":访问路径为SIM卡中的联系人总数;
  • Parameter - Max List Count = 0:获取SIM中联系人总数;

Response:

yaml 复制代码
OBEX Protocol
    [Profile: PBAP (4)]
    [Current Path: /]
    .010 0000 = Response Code: Success (0x20)
    1... .... = Final Flag: True
    Packet Length: 11
    [Request in Frame: 490]
    Headers
        Connection Id: 1
            Header Id: Connection Id (0xcb)
                11.. .... = Encoding: 4 byte quantity (network order) (0x3)
                ..00 1011 = Meaning: Connection Id (0x0b)
            Connection ID: 1
        End Of Body
            Header Id: End Of Body (0x49)
                01.. .... = Encoding: Byte sequence, length prefixed with 2 byte Unsigned Integer (0x1)
                ..00 1001 = Meaning: End Of Body (0x09)
            Length: 3
            Value: <MISSING>
  • End or Body:

    • MaxListCount != 0:返回Name对应的数据,回复数据中的vCard对象只应包含使用属性选择器Attribute Selector参数指示的属性,并且应使用格式Format参数指示的格式组装数据;
    • MaxListCount == 0:直接返回,代表没有获取的数据;
同步 All 联系人

Request:

yaml 复制代码
OBEX Protocol
    [Profile: PBAP (4)]
    [Current Path: /]
    .000 0011 = Opcode: Get (0x03)
    1... .... = Final Flag: True
    Packet Length: 83
    [Response in Frame: 553]
    Headers
        Connection Id: 1
            Header Id: Connection Id (0xcb)
                11.. .... = Encoding: 4 byte quantity (network order) (0x3)
                ..00 1011 = Meaning: Connection Id (0x0b)
            Connection ID: 1
        Name: "telecom/pb.vcf"
            Header Id: Name (0x01)
                00.. .... = Encoding: Null terminated Unicode text, length prefixed with 2 byte Unsigned Integer (0x0)
                ..00 0001 = Meaning: Name (0x01)
            Length: 33
            Name: telecom/pb.vcf
        Type: "x-bt/phonebook"
            Header Id: Type (0x42)
                01.. .... = Encoding: Byte sequence, length prefixed with 2 byte Unsigned Integer (0x1)
                ..00 0010 = Meaning: Type (0x02)
            Length: 18
            Type: x-bt/phonebook
        Application Parameters
            Header Id: Application Parameters (0x4c)
                01.. .... = Encoding: Byte sequence, length prefixed with 2 byte Unsigned Integer (0x1)
                ..00 1100 = Meaning: Application Parameters (0x0c)
            Length: 24
            Parameter: Max List Count
                Parameter Id: Max List Count (0x04)
                Parameter Length: 2
                Max List Count: 101 (0x0065)
            Parameter: List Start Offset
                Parameter Id: List Start Offset (0x05)
                Parameter Length: 2
                List Start Offset: 1 (0x0001)
            Parameter: Filter
                Parameter Id: Filter (0x06)
                Parameter Length: 8
                Filter: 0x00000000
                    .... .... .... .... .... .... .000 0000 = Reserved: 0x00
                    .... .... .... .... .... .... 0... .... = Proprietary Filter: False
                    0000 0000 0000 0000 0000 0000 .... .... = Reserved for Proprietary Filter Usage: 0x000000
                Filter: 0x008001af, vCard Version, Formatted Name, Structured Presentation of Name, Associated Image or Photo, Delivery Address, Telephone Number, Electronic Mail Address, Nickname
                    .... .... .... .... .... .... .... ...1 = vCard Version: True
                    .... .... .... .... .... .... .... ..1. = Formatted Name: True
                    .... .... .... .... .... .... .... .1.. = Structured Presentation of Name: True
                    .... .... .... .... .... .... .... 1... = Associated Image or Photo: True
                    .... .... .... .... .... .... ...0 .... = Birthday: False
                    .... .... .... .... .... .... ..1. .... = Delivery Address: True
                    .... .... .... .... .... .... .0.. .... = Delivery: False
                    .... .... .... .... .... .... 1... .... = Telephone Number: True
                    .... .... .... .... .... ...1 .... .... = Electronic Mail Address: True
                    .... .... .... .... .... ..0. .... .... = Electronic Mail: False
                    .... .... .... .... .... .0.. .... .... = Time Zone: False
                    .... .... .... .... .... 0... .... .... = Geographic Position: False
                    .... .... .... .... ...0 .... .... .... = Job: False
                    .... .... .... .... ..0. .... .... .... = Role within the Organization: False
                    .... .... .... .... .0.. .... .... .... = Organization Logo: False
                    .... .... .... .... 0... .... .... .... = vCard of Person Representing: False
                    .... .... .... ...0 .... .... .... .... = Name of Organization: False
                    .... .... .... ..0. .... .... .... .... = Comments: False
                    .... .... .... .0.. .... .... .... .... = Revision: False
                    .... .... .... 0... .... .... .... .... = Pronunciation of Name: False
                    .... .... ...0 .... .... .... .... .... = Uniform Resource Locator: False
                    .... .... ..0. .... .... .... .... .... = Unique ID: False
                    .... .... .0.. .... .... .... .... .... = Public Encryption Key: False
                    .... .... 1... .... .... .... .... .... = Nickname: True
                    .... ...0 .... .... .... .... .... .... = Categories: False
                    .... ..0. .... .... .... .... .... .... = Product ID: False
                    .... .0.. .... .... .... .... .... .... = Class Information: False
                    .... 0... .... .... .... .... .... .... = String Used For Sorting Operations: False
                    ...0 .... .... .... .... .... .... .... = Timestamp: False
                    000. .... .... .... .... .... .... .... = Reserved: 0x0
            Parameter: Format
                Parameter Id: Format (0x07)
                Parameter Length: 1
                Format: 3.0 (0x01)
  • Name = "telecom/pb.vcf":加载手机中的联系人;

  • Type = "x-bt/phonebook":对应了Download Feature中的PullPhonebook Function;

  • Application Parameters

    • Parameter - Max List Count = 101:手机中联系人最大的count = 101;

    • Parameter - List Start Offset = 1:代表了从通讯录的第一个位置开始加载;

    • Parameter - Filter:过滤器,Parameter Id = 0x06,对应Application Parameters表格中其实为PropertySelector

      其中需要获取vCard Version, Formatted Name, Structured Presentation of Name, Associated Image or Photo, Delivery Address, Telephone Number, Electronic Mail Address, Nickname信息;

    • Parameter - Format = 3.0:这个其实是根据vCard Version来决定的,目前使用 version = 3.0 的Format;

其中我们涉及到了Filter,在这个模块中,规定了哪些属性是需要过滤,哪些属性是需要保留:

Name Filter Name Filter
VERSION true NOTE false
FN true REV false
N true SOUND false
PHOTO true URL false
BDAY false UID false
ADR true KEY false
LABEL false NICKNAME false
TEL true CATEGORIES false
EMAIL true PROID false
MAILER false CLASS false
TZ false SORT-STRING false
GEO false X-IRMC-CALL-DATETIME false
TITLE false X-BT-SPEEDDIALKEY false
ROLE false X-BT-UCI false
LOGO false X-BT-UID false
AGENT false PROPRIETARY FILTER false
ORG false

Response:

响应过程分为两个部分:

  • 数据帧连续响应上报;
  • 汇总信息及数据文本信息上报;
数据帧连续响应上报
yaml 复制代码
Frame 495: 1004 bytes on wire (8032 bits), 1004 bytes captured (8032 bits)
..............................
OBEX Protocol
    [Profile: PBAP (4)]
    [Current Path: /]
    Reassembled OBEX in frame: 553
    Data (990 bytes)
        Data: a0ac17cb0000000149ac0f424547494e3a56434152440d0a...
        [Length: 990]

这一帧数据为同步指令下发后上报的第一帧数据,在Data参数中描述了联系人信息;

汇总信息及数据文本信息上报

上述的过程中通过PropertySelector设置了属性可见性;

ini 复制代码
OBEX Protocol
    [Profile: PBAP (4)]
    [Current Path: /]
    [45 OBEX Fragments (44055 bytes): #495(990), #496(990), #497(990), #498(990), #499(990), #500(990), #502(990), #503(990), #505(990), #506(990), #507(990), #508(990), #510(990), #512(990), #513(990), #514(990), #515(990), #516(990), #518(990]
        [Frame: 495, payload: 0-989 (990 bytes)]
        [Frame: 496, payload: 990-1979 (990 bytes)]
        ..............................
        [Frame: 553, payload: 43560-44054 (495 bytes)]
        [Fragment count: 45]
        [Reassembled OBEX length: 44055]
    .010 0000 = Response Code: Success (0x20)
    1... .... = Final Flag: True
    Packet Length: 44055
    [Request in Frame: 493]
    Headers
        Connection Id: 1
            Header Id: Connection Id (0xcb)
                11.. .... = Encoding: 4 byte quantity (network order) (0x3)
                ..00 1011 = Meaning: Connection Id (0x0b)
            Connection ID: 1
        End Of Body
            Header Id: End Of Body (0x49)
                01.. .... = Encoding: Byte sequence, length prefixed with 2 byte Unsigned Integer (0x1)
                ..00 1001 = Meaning: End Of Body (0x09)
            Length: 44047
            Value: 424547494e3a56434152440d0a56455253494f4e3a332e30...
    Line-based text data: x-bt/phonebook (1088 lines)
        BEGIN:VCARD\r\n
        VERSION:3.0\r\n
        N:;胡#;;;\r\n
        FN:胡#\r\n
        TEL;TYPE=CELL:610xxx\r\n
        END:VCARD\r\n
        BEGIN:VCARD\r\n
        VERSION:3.0\r\n
        N:;杜##;;;\r\n
        FN:杜##\r\n
        TEL;TYPE=CELL:184xxxxxxxx\r\n
        END:VCARD\r\n
        BEGIN:VCARD\r\n
        VERSION:3.0\r\n
        N:;太####;;;\r\n
        FN:太####\r\n
        TEL;TYPE=CELL:156xxxxxxxx\r\n
        TEL;TYPE=CELL:135xxxxxxxx\r\n
        END:VCARD\r\n
        
        ..............................
        
        BEGIN:VCARD\r\n
        VERSION:3.0\r\n
        N:;郭##;;;\r\n
        FN:郭##\r\n
        TEL;TYPE=CELL:135xxxxxxxx\r\n
        PHOTO;ENCODING=B;TYPE=JPEG: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\r\n
        \r\n
        END:VCARD\r\n
        
        ..............................

这一块就是响应PullPhonebook Function的结果;

  • OBEX Fragments:代表了数据帧,每一帧数据中有可能包含多组联系人方式,第一帧数据就是从Frame 495开始;
  • Fragment count:读取所有联系人所使用的Frame count;
  • Response Code:Success;
  • End Of Body:因为在Request中 MaxListCount != 0,所以其中的value不是标识,而是按照请求的指令组织的数据响应;
  • Line-based text data:数据响应的文本内容;

接下来就是vCard Object内容的描述了;

  • BEGIN:VCARD:一组联系人信息开始标志
  • END:VCARD:结束标志
  • VERSION:版本
  • FN:姓名
  • TEL;TYPE=CELL:联系人联系方式
  • PHOTO;ENCODING=B;TYPE=JPEG:联系人头像

我们在上述过程中,其实对很多属性都进行了保留,但是需要确保手机联系人信息中包含这些属性,例如联系人头像这一属性,很多联系人方式中并没有设置,所以同步下来的信息中没有该属性的描述,只有在极少数的联系人信息中设置过,所以会同步头像信息;

同步 SIM 联系人方式和同步手机联系人方式一样,只是在SIM卡中没有保存联系人,所有获取到的信息为空,Parameter - End Of Body的value标识为;

同步通话记录

获取 All CCH Count

同步所有的通话记录;

Request:

yaml 复制代码
OBEX Protocol
    [Profile: PBAP (4)]
    [Current Path: /]
    .000 0011 = Opcode: Get (0x03)
    1... .... = Final Flag: True
    Packet Length: 72
    [Response in Frame: 566]
    Headers
        Connection Id: 1
            Header Id: Connection Id (0xcb)
                11.. .... = Encoding: 4 byte quantity (network order) (0x3)
                ..00 1011 = Meaning: Connection Id (0x0b)
            Connection ID: 1
        Name: "telecom/cch.vcf"
            Header Id: Name (0x01)
                00.. .... = Encoding: Null terminated Unicode text, length prefixed with 2 byte Unsigned Integer (0x0)
                ..00 0001 = Meaning: Name (0x01)
            Length: 35
            Name: telecom/cch.vcf
        Type: "x-bt/vcard-listing"
            Header Id: Type (0x42)
                01.. .... = Encoding: Byte sequence, length prefixed with 2 byte Unsigned Integer (0x1)
                ..00 0010 = Meaning: Type (0x02)
            Length: 22
            Type: x-bt/vcard-listing
        Application Parameters
            Header Id: Application Parameters (0x4c)
                01.. .... = Encoding: Byte sequence, length prefixed with 2 byte Unsigned Integer (0x1)
                ..00 1100 = Meaning: Application Parameters (0x0c)
            Length: 7
            Parameter: Max List Count
                Parameter Id: Max List Count (0x04)
                Parameter Length: 2
                Max List Count: 0 (0x0000)
  • Name = "telecom/cch.vcf":代表了需要加载或访问的数据为所有通话记录;

  • Type = "x-bt/vcard-listing":获取感兴趣的Phone Object 列表;

  • Application Parameters

    • Parameter - Max List Count = 0:= 0的情况下,表明本次Request获取的是符合条件的所有信息的Count;

Response:

yaml 复制代码
OBEX Protocol
    [Profile: PBAP (4)]
    [Current Path: /]
    .010 0000 = Response Code: Success (0x20)
    1... .... = Final Flag: True
    Packet Length: 15
    [Request in Frame: 562]
    Headers
        Connection Id: 1
            Header Id: Connection Id (0xcb)
                11.. .... = Encoding: 4 byte quantity (network order) (0x3)
                ..00 1011 = Meaning: Connection Id (0x0b)
            Connection ID: 1
        Application Parameters
            Header Id: Application Parameters (0x4c)
                01.. .... = Encoding: Byte sequence, length prefixed with 2 byte Unsigned Integer (0x1)
                ..00 1100 = Meaning: Application Parameters (0x0c)
            Length: 7
            Parameter: Phonebook Size
                Parameter Id: Phonebook Size (0x08)
                Parameter Length: 2
                Phonebook Size: 1631 (0x065f)
  • Phonebook Size = 1631:代表所有的通话记录信息为1631条;
同步 All CCH

Request:

yaml 复制代码
OBEX Protocol
    [Profile: PBAP (4)]
    [Current Path: /]
    .000 0011 = Opcode: Get (0x03)
    1... .... = Final Flag: True
    Packet Length: 71
    [Response in Frame: 578]
    Headers
        Connection Id: 1
            Header Id: Connection Id (0xcb)
                11.. .... = Encoding: 4 byte quantity (network order) (0x3)
                ..00 1011 = Meaning: Connection Id (0x0b)
            Connection ID: 1
        Name: "telecom/cch.vcf"
            Header Id: Name (0x01)
                00.. .... = Encoding: Null terminated Unicode text, length prefixed with 2 byte Unsigned Integer (0x0)
                ..00 0001 = Meaning: Name (0x01)
            Length: 35
            Name: telecom/cch.vcf
        Type: "x-bt/phonebook"
            Header Id: Type (0x42)
                01.. .... = Encoding: Byte sequence, length prefixed with 2 byte Unsigned Integer (0x1)
                ..00 0010 = Meaning: Type (0x02)
            Length: 18
            Type: x-bt/phonebook
        Application Parameters
            Header Id: Application Parameters (0x4c)
                01.. .... = Encoding: Byte sequence, length prefixed with 2 byte Unsigned Integer (0x1)
                ..00 1100 = Meaning: Application Parameters (0x0c)
            Length: 10
            Parameter: Max List Count
                Parameter Id: Max List Count (0x04)
                Parameter Length: 2
                Max List Count: 50 (0x0032)
            Parameter: Format
                Parameter Id: Format (0x07)
                Parameter Length: 1
                Format: 3.0 (0x01)
  • Name = "telecom/cch.vcf":被访问加载的数据文件路径;

  • Type = "x-bt/phonebook":同步通话记录;

  • Application Parameters

    • Parameter - Max List Count = 50:本次Request需要同步的最大的信息数
    • Parameter - Format:版本格式为3.0格式;

Response:

yaml 复制代码
Frame 578: 61 bytes on wire (488 bits), 61 bytes captured (488 bits)
Bluetooth
    [Source: HuaweiDe_42:c7:dd (30:aa:e4:42:c7:dd)]
    [Destination: BarrotTe_50:67:20 (04:7f:0e:50:67:20)]
Bluetooth HCI H4
    [Direction: Rcvd (0x01)]
    HCI Packet Type: ACL Data (0x02)
Bluetooth HCI ACL Packet
    .... 0000 0000 0010 = Connection Handle: 0x002
    ..10 .... .... .... = PB Flag: First Automatically Flushable Packet (2)
    00.. .... .... .... = BC Flag: Point-To-Point (0)
    Data Total Length: 56
    Data
    [Connect in frame: 109]
    [Source BD_ADDR: HuaweiDe_42:c7:dd (30:aa:e4:42:c7:dd)]
    [Source Device Name: dupz]
    [Source Role: Slave (2)]
    [Destination BD_ADDR: BarrotTe_50:67:20 (04:7f:0e:50:67:20)]
    [Destination Device Name: HAVAL_6720]
    [Destination Role: Master (1)]
    [Last Role Change in Frame: 107]
    [Current Mode: Active Mode (0)]
    [Last Mode Change in Frame: 564]
Bluetooth L2CAP Protocol
    Length: 52
    CID: Dynamically Allocated Channel (0x0041)
    [Connect in frame: 178]
    [PSM: RFCOMM (0x0003)]
Bluetooth RFCOMM Protocol
    Address: E/A flag: 1, C/R flag: 0, Direction: 0, Channel: 19
        1001 10.. = DLCI: 0x26 (Direction: 0, Channel: 19)
            1001 1... = Channel: 19
            .... .0.. = Direction: 0x0
        .... ..0. = C/R Flag: Response (0x0)
        .... ...1 = EA Flag: Last field octet (0x1)
    Control: Frame type: Unnumbered Information with Header check (UIH) (0xef), P/F flag: 1
        ...1 .... = P/F flag: 0x1
        111. 1111 = Frame type: Unnumbered Information with Header check (UIH) (0xef)
    Payload length: 47
    Credits: 1
    Frame Check Sequence: 0xe1
OBEX Protocol
    [Profile: PBAP (4)]
    [Current Path: /]
    [8 OBEX Fragments (6977 bytes): #569(990), #570(990), #571(990), #572(990), #573(990), #574(990), #576(990), #578(47)]
        [Frame: 569, payload: 0-989 (990 bytes)]
        ..............................
        [Frame: 578, payload: 6930-6976 (47 bytes)]
        [Fragment count: 8]
        [Reassembled OBEX length: 6977]
    .010 0000 = Response Code: Success (0x20)
    1... .... = Final Flag: True
    Packet Length: 6977
    [Request in Frame: 567]
    Headers
        Connection Id: 1
            Header Id: Connection Id (0xcb)
                11.. .... = Encoding: 4 byte quantity (network order) (0x3)
                ..00 1011 = Meaning: Connection Id (0x0b)
            Connection ID: 1
        End Of Body
            Header Id: End Of Body (0x49)
                01.. .... = Encoding: Byte sequence, length prefixed with 2 byte Unsigned Integer (0x1)
                ..00 1001 = Meaning: End Of Body (0x09)
            Length: 6969
            Value: 424547494e3a56434152440d0a56455253494f4e3a332e30...
    Line-based text data: x-bt/phonebook (350 lines)
        BEGIN:VCARD\r\n
        VERSION:3.0\r\n
        FN:\r\n
        N:\r\n
        TEL;TYPE=0:03511008611\r\n
        X-IRMC-CALL-DATETIME;TYPE=DIALED:20220609T145831\r\n
        END:VCARD\r\n
        BEGIN:VCARD\r\n
        VERSION:3.0\r\n
        FN:\r\n
        N:\r\n
        TEL;TYPE=0:03511008611\r\n
        X-IRMC-CALL-DATETIME;TYPE=DIALED:20220609T143109\r\n
        END:VCARD\r\n
        BEGIN:VCARD\r\n
        VERSION:3.0\r\n
        FN:\r\n
        N:\r\n
        TEL;TYPE=0:131xxxxxxxx\r\n
        X-IRMC-CALL-DATETIME;TYPE=RECEIVED:20220608T184054\r\n
        END:VCARD\r\n
        BEGIN:VCARD\r\n
        VERSION:3.0\r\n
        FN:\r\n
        N:\r\n
        TEL;TYPE=0:03511008611\r\n
        X-IRMC-CALL-DATETIME;TYPE=DIALED:20220608T092034\r\n
        END:VCARD\r\n
        ........................
        BEGIN:VCARD\r\n
        VERSION:3.0\r\n
        FN;CHARSET=UTF-8:中通快递\r\n
        N;CHARSET=UTF-8:中通快递\r\n
        TEL;TYPE=0:95720\r\n
        X-IRMC-CALL-DATETIME;TYPE=DIALED:20220606T142440\r\n
        END:VCARD\r\n
        BEGIN:VCARD\r\n
        VERSION:3.0\r\n
        FN;CHARSET=UTF-8:中通快递\r\n
        N;CHARSET=UTF-8:中通快递\r\n
        TEL;TYPE=0:95720\r\n
        X-IRMC-CALL-DATETIME;TYPE=MISSED:20220606T141702\r\n
        END:VCARD\r\n
        ........................

在本次的Response中,一共返回了50组通话记录信息,对应了Request中的MaxListCount = 50;

我们发现,在这50组信息中,有很多相同的来电或者是去电信息,他们以发生的时间节点作为唯一标识;

makefile 复制代码
BEGIN:VCARD\r\n
VERSION:3.0\r\n
FN:\r\n
N:\r\n
TEL;TYPE=0:03511008611\r\n
X-IRMC-CALL-DATETIME;TYPE=DIALED:20220609T145831\r\n
END:VCARD\r\n
  • BEGIN:VCARD:一组通话记录信息开始标志

  • END:VCARD:结束标志

  • VERSION:版本

  • N:姓名,现在的这组信息中为空,因为在一般情况下,我们手机中保存的联系人来电时,会提示Name Info,如果是陌生号码,一般直接显示电话号码,无法显示Name Info,但是存在一种情况:公共类型的电话号码是默认支持的,例如外卖、快递、中国移动、中国联通类似性质的号码是无需备注,来电时可以直接显示Name;

    • CHARSET=UTF-8:针对中文Name,采用UTF-8的编码方式
  • TEL;TYPE=0:联系人联系方式

  • X-IRMC-CALL-DATETIME:发生的时间点

  • X-IRMC-CALL-DATETIME;TYPE:通话记录类型

    • TYPE=DIALED:拨号,去电
    • TYPE=RECEIVED:来电
    • TYPE=MISSED:未接
相关推荐
吃汉堡吃到饱1 小时前
【Android】浅析MVC与MVP
android·mvc
深海呐7 小时前
Android AlertDialog圆角背景不生效的问题
android
ljl_jiaLiang7 小时前
android10 系统定制:增加应用使用数据埋点,应用使用时长统计
android·系统定制
花花鱼7 小时前
android 删除系统原有的debug.keystore,系统运行的时候,重新生成新的debug.keystore,来完成App的运行。
android
canonical_entropy9 小时前
金蝶云苍穹的Extension与Nop平台的Delta的区别
后端·低代码·架构
落落落sss9 小时前
sharding-jdbc分库分表
android·java·开发语言·数据库·servlet·oracle
沛沛老爹10 小时前
服务监控插件全览:提升微服务可观测性的利器
微服务·云原生·架构·datadog·influx·graphite
huaqianzkh11 小时前
了解华为云容器引擎(Cloud Container Engine)
云原生·架构·华为云
消失的旧时光-194311 小时前
kotlin的密封类
android·开发语言·kotlin
Kika写代码11 小时前
【基于轻量型架构的WEB开发】【章节作业】
前端·oracle·架构