1. 程式人生 > >[Bluetooth]: android 平臺上BLE連線流程之優化方案

[Bluetooth]: android 平臺上BLE連線流程之優化方案

  這是一篇關於之前工作成果的補記。我之前在一家可穿戴裝置公司工作,主要工作之一是幫助改進和維護本司的android手機App和本司可穿戴裝置(下文簡稱裝置)之間藍芽通訊效能。曾經有一個性能問題困擾了公司很久,就是android手機app和裝置之間的(藍芽)同步成功率很低。相比於iOS手機App和所有裝置之間輕鬆90%+的同步成功率,我們的Android App和各種裝置的同步成功率僅僅70%~80%,GoogleStore上面使用者對於我們app的差評一半以上跟“裝置難以同步”有關。 於是公司決心徹底解決這個問題,我被徵調以技術攻關。在經過了不斷的嘗試後,我們終於比較圓滿的解決了這個問題。

  首先當然是分析問題。我們對android使用者同步失敗的具體環節在程式碼裡做了追蹤,分析了至少前後半年的資料。我們發現在所有失敗原因裡,連線失敗大約佔六到七成,其餘的包括掃描超時,連線引數設定失敗,藍芽讀取檔案失敗等等。所以,我們的重點自然是藍芽連線失敗。在網上能夠搜到有關Android平臺上藍芽效能不好的很多帖子,基本沒有形成立竿見影的解決方案。我只好去看程式碼,反覆閱讀我們自己App呼叫藍芽的程式碼,以及android.bluetooth API的實現程式碼。android藍芽呼叫連線的示例程式碼很簡單,掃描獲取一個BluetoothDevice 後,呼叫它的connectGatt()方法,會返回一個BluetoothGatt。之後這個連線上的所有操作,包括連線狀態變化,關閉連線,讀寫檔案等,都在這個BluetoothGatt上操作。

public class BluetoothDevice {
...
public BluetoothGatt connectGatt(Context context, boolean autoConnect, BluetoothGattCallback callback)
}
我注意到我們App的舊程式碼中也有對於初次連線失敗的處理,它呼叫了BluetoothGatt.connect()
public class BluetoothGatt {
...
public boolean connect()
}
也就是直接在同樣一個BluetoothGatt上繼續再發起一次連線。可惜我們的追蹤程式碼顯示,這裡的嘗試重連在實際中的成功率非常之低,近乎無效。 顯然我們面臨的問題,現在變成了如何設計一個性能更好的連線(重連)邏輯。

  第一處引起我懷疑的就是舊程式碼中的重連函式呼叫。基於以前在網路程式設計方面的經歷,我覺得BluetoothGatt的行為和TCP/IP的socket

很像。socket在通訊通道的兩端各有一個,如果有異常發生,那麼一方就關閉自己的socket,對端也會相應關閉socket。在C/S架構下,client向server重新發起連線,server收到後建立一個新的socket進行通訊。所以,我覺得在每次重連時,應該使用一個全新的BluetoothGatt, 即呼叫BluetootDevice.connectGatt(Context, boolean, BluetoothGattCallback),而不是繼續使用舊的BluetoothGatt.connect()。

  接著,考慮到藍芽連線失敗在程式碼形式上分兩種,要麼是callback遲遲無返回導致超時,要麼是callback返回錯誤結果。這樣我們需要一個藍芽連線成功耗時的經驗值。 於是我們寫了一個android上的小工具,反覆向裝置發起連線,建立連線後簡單讀取資訊,關閉連線,再重連。基於重複多次的實驗中重新成功連線的耗時分佈,得到我們需要的連線耗時經驗值。

  另外,我們在網上搜到了一些帖子,建議Android上在藍芽關閉一箇舊連線,發起一個新連線之間,最好留出一定的延時。我們也把這項引數加入了測試工具中,反覆實驗不同時間間隔下重連的成功率。

綜合以上的思路,我們得到了如下的藍芽重連邏輯:


新的藍芽連線邏輯包括:在整個connect()方法內部,設有一個最多內部重連次數的引數,和一個總執行時間的引數,兩引數均可配置;在每次內部嘗試連線時,首先更新BluetoothGatt物件;在需要關閉一個藍芽連線時,先“斷開”,再“關閉”;在每次對BluetoothGatt連線,(藍芽)握手,斷開的單獨呼叫中,都添加了超時控制。

  當然,在實際執行中,還會有一些事先沒想到的情況。比如,internalConnect()如果當次連線成功後,如何防止connectTimer在喚醒後的干擾?是去立即終止這個timer呢,還是別的辦法? 這個問題留給讀者自己去思考吧。

結局:很幸運,這個解決方案在上線後效果出乎意料的好。僅僅因為這一版改動,我們的Android裝置(藍芽)同步成功率就上升到90%以上,終於能和iOS裝置的同步成功率持平了,Thank Godness!