基于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 |
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:未接