蓝牙SDP协议概述

之前写了一篇 bluedroid对于sdp的实现的源码分析   ,他其实对于sdp 协议本身的分析并不多,而是侧重于 sdp 处于Android bluedroid 架构中的代码流程,这篇文章,是针对SDP 的规范来整理SDP 协议本身的一些要点。

 

概要:

我们想一想,两个陌生的设备(之前未有过交互)如何去发现对方支持什么服务呢?很容易想到,我们需要一种协议,这种协议规定了服务在服务器上面是如何存储的以及对方如何能够通过这个协议来获取到数据,以及双方共同遵守的一些规定等等。

SDP全称是Service Discovery Protocol,它是一种服务发现的协议,它可以达成我们上面提出的问题。这部分参考core_spec,Vol3-PartB。

这样的一个协议应该具体实现一些什么?

那肯定是会规定特定的数据格式,以及交互的流程。

下面就分如下的几部分来介绍SDP:

  1. 基本概念。
  2. 数据格式
  3. 交互流程
  4. 实例

 

基本概念:

Service Record:服务就是可以提供特定信息或者进行特定的行为,或者是能进行控制某些资源的一个实体。它的实现可以基于软件或者硬件,也可以是两者兼有。在服务器上面维护的关于一个servcie的所有信息的集合就是一个service record。它的所有信息往往都是用service attributes来表示的。

service attribute:它是对于service 各种属性的一种描述。比如service ID,service的name。一些常见的属性如下:

 

 

 

从上面的图中发现service attribute 由 attribute ID和attribute Value组成的。

 

Attribute ID:它是一个16位的无符号整数,它用来区分在同一个Service Record之中的不同attribute,同时它也往往暗含与它相关的     Attribute Value的语义。注意它的用data element 来表示的。

Attribute Value:它是一串不定长的数据,它的含义是由与它对应的Attribute ID以及它所在的service类别来决定的。注意它的数据格式的是data element。(后续介绍)

 

Service class:它就是一种service的类别,它提供了所有属于这个类别的attributes的定义,它类似面向对象编程里面的类,具体的service是类的实例,一个具体的service 它可能隶属多个类别。类似面向对象的里面的继承。当然每个class本身也是要和别的class来做以区分的,承担这项任务的变量叫service class identifier,在service里面总由一个attribute叫做ServiceClassIDList,这个service class identifier就存储在这个attribute的attribute value 里面,这个值是一个UUID。

 

UUID:A UUID is a universally unique identifier that is guaranteed to be unique across all space and all time。注意它具有全局的唯一性。 它是128bit的值。

 

Service Search Patterns:这个是一串UUID,是用来搜索用的。

 

Data element:它由header和data两部分组成。其中,header部分又由两部分组成:类型描述符和大小描述符,前者是来描述data的类别,后者是来描述data 的大小。此概念非常重要。类型描述符是用header部分的高5bits来表示的。大小描述符是用header部分的低3个字节来描述的。下面看看这两个描述符具体的类别以及大小:

 

 

下面举个例子来说明:

接下来 我们看看:

数据格式:

数据的格式如下图:

PDU ID 表示这个PDU是作用,是用以区别其他的PDU

TransactionID:用以区别其他的Transaction

另外还有一个概念Continuation State:当SDP 服务器返回client 结果的时候,如果数据太大,那么就会分包,下面额度变量就是分包的标志,如果部分包,其值为0

接下来 ,我们看看交互的基本的流程:

交互流程:

根据PUD id 的不同,交互的流程也不同,但是思路都是一样,都是CS的架构。

因为基本上面所有的交互流程都是一样的,下面只讲其中一个交互的流程。

下面来解析一下它的参数:

ServiceSearchPattern:这个匹配模式是由一串UUID组成的,一次最多包含12个UUID,UUID的表现形式是data element

 

MaximumAttributeByteCount:从response中返回的最大的PDU

AttributeIDList:这个参数包含的是一串attribute ID或者是attribute ID的范围,也可以是两者的组合。

ContinuationState: 这个参数的第一个字节代表长度,然后后面跟该长度个字节。这个state 是从reponse中返回的。然后再一次请求的时候放在参数里面。如何没有剩余的字节需要读取,那么设置为0

 

下面是对应的response 的PDU:

 

相应的参数解释如下:

AttributeListsByteCount:这里是count就是AttributeLists这里的字节数。

AttributeLists:这里的元素都是data element sequence,它是由attribute IDs和attribute values 来组成的pair

 

这里先结合btsnoop来分析一下,具体的SDP 流程是怎么样的?

相应的log:btsnoop_a2dp.cfa  

从上面的log 可以看出,其PDU ID: SDP_ServiceSearchAttributeRequest ,这个命令是要先根据patterns来搜索特定的service,然后在搜索到service里面进行attribute的搜索。那么我们看看这条命名对应的具体参数。

我们应该还记得  pattern是第一个参数,其中包含的UUID是L2cap,那意味着只要包含L2cap的service都会match这个pattern,接下来的参数是说最多返回656 个字节。接下来的参数AttributeLists上面讲过,既可以是UUID,也可以是UUID的范围。这里参数是0x00 --0xFF

也就是说 返回match pattern的service的所有的attribute。

SDP里面是有专门的PDU来做browsing的,这里不作介绍。从上面的描述可以看出,虽然它没有做browsing,但是也相当于是browsing。

 

接下来,我们看看对应这个request的response:

 

 

我们按照数据格式,来分析一下,如果忘记了PDU的数据格式,可以回头看看上面写的。

07:PDU ID: SDP_ServiceSearchAttributeResponse

00 00 :Transaction ID: 0x0000

00 2b:Parameter Length: 43

根据 数据包格式,我们知道接下来是Parameters了,我们再次把这个parameter相关的PDU 放在这里:

00 26:Attribute List Byte Count: 38 代表这一包数据的AttributeLists 的byte的数量。

接下来就是AttributeLists的表达方式:

从上面的图可以知道其是Data Element Sequence

接着分析:

 0x36  0x01 0xd7 = 0b00110 0b110 0x01 0xd7

   其中0b00110 说明Type是 Data element sequence 

0b110 说明参数的长度部分是由16个bits来表示的,也就是后面的0x01 0xd7,这个长度代表所有的返回的参数的长度,(后续的包是分包返回)并不是这个包的长度。这里还需要注意一点的是这里的type是Data element sequence ,意味着接下来parameter部分都是Data element的格式。

接着分析:

接下来肯定还是data element的header部分

36 00 3b :0b00110 0b110 0x00 0x3b 说明接下来的 AttributeList 里面的数据元素还是Data Element,并且 这个AttributeList的长度是的0x003b ,

接下来的数据是 :

09 00 00  = 0b00001 0b001 00 00 对应上面的data element说明Attribute ID的Type是Unsigned Integer,(注意根据上面的格式,第一个element是Attribute ID,接着是Attribute value),Attribute ID的SizeIndex是2 bytes,Attribute ID = 0x00 0x00

下面看下一个element 这个element 是对应上面的Attribute ID的Attribute value:

0a 00 01 00 00  = 0b00001 0b010 说明这个data element的Type是Unsigned Integer,用4个字节来表示 也即00 01 00 00

 

接下来的就是 下一个 attribute 了,其格式都是类似,只是代表的attribute不同。在此不再赘述。

 

最后再举个profile的例子,看看profile中是如何定义它的service的:

这里看A2dp 中关于其自身service的描述:这里只描述sink的情况:

从上面的service class ID 看出它是一个audio sink的service,涉及到protocol 有L2cap和AVDTP,与其相对应的profile 是A2dp

Supported Features是它有可能支持的feature,接下来还有provider name和Service name的描述。

下面看一下log实际的 搜索的情况,和上面的规范是一致:

 

 


end

 

posted @ 2018-08-18 22:24  雪山飞燕  阅读(11021)  评论(4编辑  收藏  举报