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