以前寫了一篇 bluedroid對於sdp的實現的源碼分析 ,他其實對於sdp 協議自己的分析並很少,而是側重於 sdp 處於Android bluedroid 架構中的代碼流程,這篇文章,是針對SDP 的規範來整理SDP 協議自己的一些要點。html
概要:
咱們想想,兩個陌生的設備(以前未有過交互)如何去發現對方支持什麼服務呢?很容易想到,咱們須要一種協議,這種協議規定了服務在服務器上面是如何存儲的以及對方如何可以經過這個協議來獲取到數據,以及雙方共同遵照的一些規定等等。編程
SDP全稱是Service Discovery Protocol,它是一種服務發現的協議,它能夠達成咱們上面提出的問題。這部分參考core_spec,Vol3-PartB。服務器
這樣的一個協議應該具體實現一些什麼?架構
那確定是會規定特定的數據格式,以及交互的流程。ide
下面就分以下的幾部分來介紹SDP:oop
- 基本概念。
- 數據格式
- 交互流程
- 實例
基本概念:
Service Record:服務就是能夠提供特定信息或者進行特定的行爲,或者是能進行控制某些資源的一個實體。它的實現能夠基於軟件或者硬件,也能夠是二者兼有。在服務器上面維護的關於一個servcie的全部信息的集合就是一個service record。它的全部信息每每都是用service attributes來表示的。源碼分析
![](http://static.javashuo.com/static/loading.gif)
service attribute:它是對於service 各類屬性的一種描述。好比service ID,service的name。一些常見的屬性以下:spa
![](http://static.javashuo.com/static/loading.gif)
![](http://static.javashuo.com/static/loading.gif)
從上面的圖中發現service attribute 由 attribute ID和attribute Value組成的。htm
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個字節來描述的。下面看看這兩個描述符具體的類別以及大小:
![](http://static.javashuo.com/static/loading.gif)
![](http://static.javashuo.com/static/loading.gif)
下面舉個例子來講明:
![](http://static.javashuo.com/static/loading.gif)
接下來 咱們看看:
數據格式:
數據的格式以下圖:
![](http://static.javashuo.com/static/loading.gif)
PDU ID 表示這個PDU是做用,是用以區別其餘的PDU
TransactionID:用以區別其餘的Transaction
另外還有一個概念Continuation State:當SDP 服務器返回client 結果的時候,若是數據太大,那麼就會分包,下面額度變量就是分包的標誌,若是部分包,其值爲0
![](http://static.javashuo.com/static/loading.gif)
接下來 ,咱們看看交互的基本的流程:
交互流程:
根據PUD id 的不一樣,交互的流程也不一樣,可是思路都是同樣,都是CS的架構。
![](http://static.javashuo.com/static/loading.gif)
由於基本上面全部的交互流程都是同樣的,下面只講其中一個交互的流程。
![](http://static.javashuo.com/static/loading.gif)
下面來解析一下它的參數:
ServiceSearchPattern:這個匹配模式是由一串UUID組成的,一次最多包含12個UUID,UUID的表現形式是data element
MaximumAttributeByteCount:從response中返回的最大的PDU
AttributeIDList:這個參數包含的是一串attribute ID或者是attribute ID的範圍,也能夠是二者的組合。
ContinuationState: 這個參數的第一個字節表明長度,而後後面跟該長度個字節。這個state 是從reponse中返回的。而後再一次請求的時候放在參數裏面。如何沒有剩餘的字節須要讀取,那麼設置爲0
下面是對應的response 的PDU:
![](http://static.javashuo.com/static/loading.gif)
相應的參數解釋以下:
AttributeListsByteCount:這裏是count就是AttributeLists這裏的字節數。
AttributeLists:這裏的元素都是data element sequence,它是由attribute IDs和attribute values 來組成的pair
這裏先結合btsnoop來分析一下,具體的SDP 流程是怎麼樣的?
相應的log:btsnoop_a2dp.cfa
![](http://static.javashuo.com/static/loading.gif)
從上面的log 能夠看出,其PDU ID: SDP_ServiceSearchAttributeRequest ,這個命令是要先根據patterns來搜索特定的service,而後在搜索到service裏面進行attribute的搜索。那麼咱們看看這條命名對應的具體參數。
![](http://static.javashuo.com/static/loading.gif)
咱們應該還記得 pattern是第一個參數,其中包含的UUID是L2cap,那意味着只要包含L2cap的service都會match這個pattern,接下來的參數是說最多返回656 個字節。接下來的參數AttributeLists上面講過,既能夠是UUID,也能夠是UUID的範圍。這裏參數是0x00 --0xFF
也就是說 返回match pattern的service的全部的attribute。
SDP裏面是有專門的PDU來作browsing的,這裏不做介紹。從上面的描述能夠看出,雖然它沒有作browsing,可是也至關因而browsing。
接下來,咱們看看對應這個request的response:
![](http://static.javashuo.com/static/loading.gif)
咱們按照數據格式,來分析一下,若是忘記了PDU的數據格式,能夠回頭看看上面寫的。
07:PDU ID: SDP_ServiceSearchAttributeResponse
00 00 :Transaction ID: 0x0000
00 2b:Parameter Length: 43
根據 數據包格式,咱們知道接下來是Parameters了,咱們再次把這個parameter相關的PDU 放在這裏:
![](http://static.javashuo.com/static/loading.gif)
00 26:Attribute List Byte Count: 38 表明這一包數據的AttributeLists 的byte的數量。
接下來就是AttributeLists的表達方式:
![](http://static.javashuo.com/static/loading.gif)
從上面的圖能夠知道其是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
![](http://static.javashuo.com/static/loading.gif)
接下來的就是 下一個 attribute 了,其格式都是相似,只是表明的attribute不一樣。在此再也不贅述。
最後再舉個profile的例子,看看profile中是如何定義它的service的:
這裏看A2dp 中關於其自身service的描述:這裏只描述sink的狀況:
![](http://static.javashuo.com/static/loading.gif)
![](http://static.javashuo.com/static/loading.gif)
從上面的service class ID 看出它是一個audio sink的service,涉及到protocol 有L2cap和AVDTP,與其相對應的profile 是A2dp
Supported Features是它有可能支持的feature,接下來還有provider name和Service name的描述。
下面看一下log實際的 搜索的狀況,和上面的規範是一致:
![](http://static.javashuo.com/static/loading.gif)
end