藍芽工作流程

慢慢的燃燒發表於2017-03-22

原址:http://9105034.blog.51cto.com/9095034/1831110

1 基礎知識介紹

1.1 縮略語

BTIF: Bluetooth Interface 
BTU : Bluetooth Upper Layer 
BTM: Bluetooth Manager 
BTE: Bluetooth embedded system 
BTA :Blueetooth application layer 
CO: call out\CI: call in 
HF : Handsfree Profile 
HH: HID Host Profile 
HL: Health Device Profile 
AV:audio\vidio 
ag: audio gateway 
ar: audio/video registration 
gattc: GATT client 
BLE: Bluetooth Low Energy

1.2 android藍芽結構

這裡寫圖片描述
再把左邊的部分展開來看: 
這裡寫圖片描述 
再把它攤開來看: 
這裡寫圖片描述
程式碼分佈: 
frameworks/base/core/Java/Android/Bluetooth
frameworks/base/services/java/com/android/server/BluetoothManagerService.java
裡面提供java層使用的一些類和一些aidl檔案,供其他程式呼叫。開啟和關閉藍芽的公共介面也在這裡面。 
packages/apps/Bluetooth:對應Bluetooth.apk,作為系統的藍芽的核心程式而存在,com.android.bluetooth,呼叫framework的開啟藍芽介面後會啟動該程式。其內部實現了多種上層藍芽模式:opp,hfp,a2dp,hdp,hid等,並通過JNI呼叫與hal層完成聯絡。 
/hardware/libhardware/include/hardware/bluetooth.h: hal層介面標頭檔案 
external/bluetooth/bluedroid:bluedroid官方協議棧 
packages/apps/Settings/src/com/android/settings/Bluetooth: setting中藍芽部分,介面相關 
bluedroid藍芽的呼叫方式:從apk到framework,framework再通過binder呼叫bluetooth應用,在通過應用層利用jni呼叫hal層實現藍芽的各種請求。

1.3 協議簡介

這裡寫圖片描述

  • Core Specification(核心規範),用於規定藍芽裝置必須實現的通用功能和協議層次。它由軟體和硬體模組組成,兩個模組之間的資訊和資料通過主機控制介面(HCI)的解釋才能進行傳遞。

  • Profiles(藍芽應用規範),它從應用場景的角度為藍芽技術的使用制定了不同的規範。這也是和大眾日常生活接觸最多的一部分。藍芽支援很多Profiles,下文將介紹幾種使用最廣泛的藍芽應用規範

OPP:檔案傳輸規範 
hfp:和電話相關,接聽、結束通話電話,以及連線sco通路 
a2dp:藍芽立體聲規範,其中包含avrcp規範,avrcp規範實現了聽歌時暫停、上下歌曲選擇等控制模式。目前藍芽耳機一般都支援這兩種規範。 
hid:人機互動規範,藍芽滑鼠鍵盤等 
phap:電話號碼簿訪問協議 
hdp:藍芽醫療相關規範

2 開啟藍芽

2.1 檔案路徑

檔案路徑: 
frameworks/base/core/java/android/bluetooth/BluetoothAdapter.java 
frameworks/base/services/java/com/android/server/BluetoothManagerService.java 
packages/apps/Bluetooth/src/com/android/bluetooth/btservice/AdapterService.java 
packages/apps/Bluetooth/src/com/android/bluetooth/btservice/AdapterState.java 
packages/apps/Bluetooth/jni/com_android_bluetooth_btservice_AdapterService.cpp 
hardware/libhardware/include/hardware/bluetooth.h 
external/bluetooth/bluedroid/btif/src/bluetooth.c

2.2 上層開啟流程

先從framework提供的公共介面開始: 
開啟藍芽使用BluetoothAdapter.java提供的方法getDefaultAdapter(),該方法中先獲取BluetoothManagerService.java提供的binder物件,並且用該物件建立BluetoothAdapter例項。 
這裡寫圖片描述
獲取到BluetoothAdapter例項用,呼叫enable方法,BluetoothAdapter的enable方法會呼叫BluetoothManagerService.java的enable,直接看BluetoothManagerService.java,在其中enable方法會啟動一個service,這個service就是AdapterService。在啟動這個service之後,先不看這個service的具體動作,繼續看BluetoothManagerService會做什麼。 
這裡寫圖片描述
在啟動這個AdapterService之後,先不看這個AdapterService的具體動作,繼續看BluetoothManagerService中的執行流程。在啟動AdapterService,會回撥mConnection的onServiceConnected()方法,在該方法中傳送MESSAGE_BLUETOOTH_SERVICE_CONNECTED 訊息,在處理該訊息時,做了下面三件事: 
1、得到AdapterService返回的IBluetooth.aidl介面的實現類。 
mBluetooth = IBluetooth.Stub.asInterface(service) 
2.呼叫IBluetooth.aidl提供的介面註冊AdapterService的回撥方法。 
這樣,不僅BluetoothManagerService可以通過aidl呼叫AdapterService中的方法,也實現了AdapterService可以回撥BluetoothManagerService中的方法。回撥方法如下所示,記住這個回撥方法,後面會講到。 
mBluetooth.registerCallback(mBluetoothCallback) 
這裡寫圖片描述
3、第三件事就是呼叫IBluetooth.aidl提供的enable方法。下面就進入到AdapterService.java中。

下面就進入了package/apps下: 
首先看onBind方法,返回了一個物件mBinder。執行其中的enable方法, 
這裡寫圖片描述
呼叫mAdapterStateMachine的sendMessage方法,傳送USER_TURN_ON訊息。。AdapterState.java是一個狀態機,有以下幾種狀態: 
mOffState:關閉 
mPendingCommandState:活動,開啟中 
mOnState:開啟 
初始狀態是mOffState。

傳送訊息後,在OffState狀態下處理訊息,首先切換狀態到mPendingCommandState,然後呼叫adapterService.processStart()方法。 
這裡寫圖片描述
繼續回到adapterService。執行如下程式碼,啟動手機支援的所有profile, 
這裡寫圖片描述
手機支援的所有profile如下: 
這裡寫圖片描述 
挨個啟動上面所有的服務。每個服務啟動之後都會呼叫adapterService中的notifyProfileServiceStateChanged方法。該方法中傳送MESSAGE_PROFILE_SERVICE_STATE_CHANGED訊息。訊息處理如下: 
這裡寫圖片描述
如果所有服務都起來之後,給狀態機AdapterState傳送訊息AdapterState.STARTED。 
根據以上流程,現在狀態機在mPendingCommandState狀態,在該狀態下處理STARTED訊息。程式碼如下: 
這裡寫圖片描述
終於看到native方法。 
對應的native方法在com_android_bluetooth_btservice_AdapterService.cpp中。呼叫了sBluetoothInterface結構體中的enable方法。該結構體的定義在bluetooth.h中,具體實現在bluetooth.c中。後面的程式碼這裡不做具體分析。 
這裡寫圖片描述

2.3 底層回撥流程

回撥主要使用 
HAL_CBACK(bt_hal_cbacks, device_found_cb, num_properties, properties); HAL_CBACK就是一巨集定義,就是呼叫結構體中對應的方法。 
這裡寫圖片描述
這裡重點看一下一個bt_callbacks_t結構體,定義在bluetooth.h中,如下 
這裡寫圖片描述
初始化在bluetooth.c中,初始化的流程。

回到AdapterService.java,在服務啟動時呼叫了initNative方法。看下jni中的initNative方法: 
這裡寫圖片描述
還是sBluetoothInterface結構體,繼續看bluetooth.c檔案,可以看到init方法中將地址sBluetoothCallbacks賦值給bt_callbacks_t,也就是,回撥結構體的地址指向了sBluetoothCallbacks,看下sBluetoothCallbacks的定義。任然在jni中定義。這樣在啟動AdapterService時將回撥地址傳入了hal層。 
這裡寫圖片描述 
最後,在驅動層完成藍芽開啟之後,會執行以下兩個回撥方法: 
adapter_properties_callback:返回手機藍芽裝置的地址、名稱、UUID等。 
adapter_state_change_callback:更新AdapterProperties中藍芽狀態,傳送廣播通知藍芽狀態變化。

具體分析下adapter_state_change_callback。對應的jni方法為:adapter_state_change_callback,方法執行以下方法。 
callbackEnv->CallVoidMethod(sJniCallbacksObj, method_stateChangeCallback, (jint)status); 
也就是回撥java層程式碼:JniCallback.java檔案中stateChangeCallback方法。這時跳轉到AdapterState.java中,執行stateChangeCallback()方法;傳送了ENABLED_READY訊息。根據以上分析,這時狀態機還處於PendingCommandState,在該狀態下處理ENABLED_READY訊息, 
這裡寫圖片描述
做下面兩個動作:狀態切換到mOnState;更新adapterProperties中的藍芽狀態資訊;通知藍芽狀態變為開啟。具體看下notifyAdapterStateChange方法。主要是呼叫了adapterService類的方法。 
adapterService.updateAdapterState(oldState, newState); 
來到adapterService類。 
這裡寫圖片描述
可以看到,看是執行該服務中註冊的回撥方法。應該還能記得,之前在開啟藍芽操作初期,在BluetoothManagerService中註冊了回撥方法。因此又跳轉到framework中,執行回撥方法。在該回撥方法中,傳送廣播通知藍芽狀態變化。

2.4 總結

藍芽開啟的流程到這裡,藍芽開啟從framework公共介面開始呼叫enable方法,執行到bluetooth.apk中,在該應用中通過jni註冊回撥方法和呼叫hal層開啟藍芽方法,在驅動層完成藍芽上電等操作後,通過hal-jni回撥到應用層中,應用通過aidl回撥通知framework藍芽狀態變化,framework傳送廣播通知大家藍芽開啟。

3 搜尋藍芽

3.1 新增程式碼路徑

packages/apps/Bluetooth/src/com/android/bluetooth/btservice/RemoteDevices.java 
packages/apps/Settings/src/com/android/settings/Bluetooth/*

3.2 搜尋過程

BluetoothSettings.java中的startScanning命令,開始搜尋。 
如果a2dp沒有在播放,就呼叫BluetoothAdapter.java中的startDiscovery()方法。 
然後又回到AdapterService中,呼叫startDiscovery方法。在該方法中直接進入到jni層。 
這裡寫圖片描述
在jni層的函式中執行如下語句,依然是該結構體。 
int ret = sBluetoothInterface->start_discovery(); 
這裡寫圖片描述 
具體的底層搜尋方法暫不往下追蹤。驅動層完成搜尋之後,返回狀態,根據返回的訊息進行處理。回撥訊息分如下幾種:包括搜尋結果返回訊息、搜尋完成訊息、搜尋取消等。 
BTA_DM_INQ_RES_EVT 
BTA_DM_INQ_CMPL_EVT 
BTA_DM_DISC_RES_EVT 
BTA_DM_DISC_BLE_RES_EVT 
BTA_DM_DISC_CMPL_EVT 
BTA_DM_DI_DISC_CMPL_EVT 
BTA_DM_SEARCH_CANCEL_CMPL_EVT

當收到搜尋結果放回訊息之後,會執行以下回撥方法。 
這裡寫圖片描述 
其中後面兩個引數:裝置屬性個數和裝置屬性。其中裝置屬性包括:地址、名稱、訊號強度等屬性。根據上面所講的回撥方法初始化,直接找到jni層的對應回撥方法,可以看到會先後呼叫以下兩個方法。 
這裡寫圖片描述
其中devicePropertyChangedCallback方法更新RemoteDevice類中的變數值。 
deviceFoundCallback方法傳送BluetoothDevice.ACTION_FOUND廣播,通知setting中要更新介面顯示該裝置。

4 藍芽配對

4.1 新增程式碼路徑

packages/apps/Settings/src/com/android/settings/Bluetooth/* 
packages/apps/Bluetooth/src/com/android/bluetooth/btservice/ BondStateMachine.java 
packages/apps/Settings/src/com/android/settings/Bluetooth/BluetoothEventManager.java 
packages/apps/Settings/src/com/android/settings/Bluetooth/CachedBluetoothDevice.java

4.2 配對過程分析

在setting中點選裝置之後開始進行配對。呼叫BluetoothDevice的createBond方法,走到AdapterService.java中的createBond方法。驅動BondStateMachine中的狀態從StableState到 
PendingCommandState。然後呼叫jni層createBondNative方法。又來到hal層介面sBluetoothInterface: 
sBluetoothInterface->create_bond((bt_bdaddr_t *)addr); 
同樣,在底層完成配對之後進行回撥: 
這裡寫圖片描述
找到對應的回撥方法,JniCallback.java中的 
void bondStateChangeCallback(int status, byte[] address, int newState) { 
mBondStateMachine.bondStateChangeCallback(status, address, newState); 
}

5 Opp檔案傳輸

只有opp的彈框是bluetooth裡,其他都是setting中彈框。

5.1 傳送檔案

點選用藍芽分享檔案後,會呼叫BluetoothOppLauncherActivity.java,其中會判斷當前藍芽是否開啟,如果沒開啟則進入BluetoothOppBtEnableActivity.java開啟藍芽,如果已經開啟,則直接進入BluetoothDevicePicker.java選擇傳輸檔案裝置選擇。

6 Map訊息訪問profile

藍芽開啟後會啟動BluetoothMapService.java 
在BluetoothMapService.java呼叫了BluetoothMapMasInstance.java的startRfcommSocketListener()方法,監聽rfcomm端的連線請求,如果有連線請求,呼叫BluetoothMapService 的 onConnect()方法,在該方法裡傳送廣播到setting中,setting彈框,使用者確認後傳送廣播ACTION_CONNECTION_ACCESS_REPLY通知BluetoothMapService,BluetoothMapService收到廣播後呼叫onConnectHandler方法,呼叫startObexServerSession方法,啟動Obex傳輸通道。

7 AVRCP

  1. 手機側主動改變狀態。註冊了一個RemoteControllerWeak(RemoteController),當手機端的播放器暫停、快進、快退、切歌等操作後,會呼叫遠端控制介面更新播放狀態、歌曲資訊。mTrackChangedNT、mPlayStatusChangedNT、mPlayPosChangedNT三個變數的值決定是否會通知對端進行同步;這三個值有jni回撥改變,即對端回撥改變。

  2. 對端主動改變狀態:1)快進、快退底層有回撥handlePassthroughCmd,來通知avrcp實時更新進度條,並同步給對端。部分車載會上報快進、快退的keycode給手機端,播放器利用RemoteController更新狀態。2)播放、暫停,對端上報keycode,播放器RemoteController控制avrcp中狀態切換

8 Pbap

類似map,連線後彈框都是廣播給setting彈框

9 功耗

之前的audiopath比較複雜,要到DSP裡面去硬解碼。現在比較簡單了,從驅動角度看,收到AF寫下來的PCM資料後,經協議棧SBC編碼後經HCI介面寫入到藍芽晶片,然後就發出去了。 
SBC編碼是針對藍芽裝置的一種音訊編碼方式,壓縮率中等,但是cpu消耗低。電話對應HFP profile,音樂對應Profile。電話使用的是同步鏈路SCO,音樂時非同步鏈路ACL,使用A2DP profile。另外還有其它profile,傳問題,獲取電話本,簡訊同步等。 
使用A2DP時,先是進行音樂的解碼,然後再把解碼後的PCM進行SBC編碼。A2DP支援下行audio編碼取樣率範圍為8k-48k。在高通的大多數方案裡面,SBC編碼是在DSP裡做的。 
HFP,有兩個角色AG和HF,正常情況下手機作為AG,耳機作為HF。但是手機程式碼中也有HF部分的程式碼 
手機藍芽晶片是三合一的,包括BT,FM和WLAN,使用一根天線。藍芽耳機和藍芽模組之間通過AT命令進行通訊,分為master和slave,誰先連對方誰就是master。藍芽功耗待機1mA左右,傳檔案要100多mA,聽音樂60左右,打電話30。


相關文章