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藍牙結(jié)構(gòu)
再把左邊的部分展開來看:
再把它攤開來看:
代碼分布:
frameworks/base/core/java/Android/Bluetooth:
frameworks/base/services/java/com/android/server/BluetoothManagerService.java:
里面提供java層使用的一些類和一些aidl文件,供其他進程調(diào)用。打開和關閉藍牙的公共接口也在這里面周崭。
packages/apps/Bluetooth:對應Bluetooth.apk湿颅,作為系統(tǒng)的藍牙的核心進程而存在,com.android.bluetooth司澎,調(diào)用framework的打開藍牙接口后會啟動該進程卓鹿。其內(nèi)部實現(xiàn)了多種上層藍牙模式:opp,hfp拄丰,a2dp,hdp俐末,hid等料按,并通過JNI調(diào)用與hal層完成聯(lián)系。
/hardware/libhardware/include/hardware/bluetooth.h: hal層接口頭文件
external/bluetooth/bluedroid:bluedroid官方協(xié)議棧
packages/apps/Settings/src/com/android/settings/Bluetooth: setting中藍牙部分卓箫,界面相關
bluedroid藍牙的調(diào)用方式:從apk到framework载矿,framework再通過binder調(diào)用bluetooth應用,在通過應用層利用jni調(diào)用hal層實現(xiàn)藍牙的各種請求烹卒。
1.3 協(xié)議簡介
Core Specification(核心規(guī)范)闷盔,用于規(guī)定藍牙設備必須實現(xiàn)的通用功能和協(xié)議層次弯洗。它由軟件和硬件模塊組成,兩個模塊之間的信息和數(shù)據(jù)通過主機控制接口(HCI)的解釋才能進行傳遞逢勾。
Profiles(藍牙應用規(guī)范)牡整,它從應用場景的角度為藍牙技術(shù)的使用制定了不同的規(guī)范。這也是和大眾日常生活接觸最多的一部分敏沉。藍牙支持很多Profiles果正,下文將介紹幾種使用最廣泛的藍牙應用規(guī)范
OPP:文件傳輸規(guī)范
hfp:和電話相關,接聽盟迟、掛斷電話秋泳,以及連接sco通路
a2dp:藍牙立體聲規(guī)范,其中包含avrcp規(guī)范攒菠,avrcp規(guī)范實現(xiàn)了聽歌時暫停迫皱、上下歌曲選擇等控制模式。目前藍牙耳機一般都支持這兩種規(guī)范辖众。
hid:人機交互規(guī)范卓起,藍牙鼠標鍵盤等
phap:電話號碼簿訪問協(xié)議
hdp:藍牙醫(yī)療相關規(guī)范
文件路徑:
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
先從framework提供的公共接口開始:
打開藍牙使用BluetoothAdapter.java提供的方法getDefaultAdapter(),該方法中先獲取BluetoothManagerService.java提供的binder對象凹炸,并且用該對象創(chuàng)建BluetoothAdapter實例戏阅。
獲取到BluetoothAdapter實例用,調(diào)用enable方法啤它,BluetoothAdapter的enable方法會調(diào)用BluetoothManagerService.java的enable奕筐,直接看BluetoothManagerService.java,在其中enable方法會啟動一個service变骡,這個service就是AdapterService离赫。在啟動這個service之后,先不看這個service的具體動作塌碌,繼續(xù)看BluetoothManagerService會做什么渊胸。
在啟動這個AdapterService之后,先不看這個AdapterService的具體動作台妆,繼續(xù)看BluetoothManagerService中的執(zhí)行流程翎猛。在啟動AdapterService,會回調(diào)mConnection的onServiceConnected()方法接剩,在該方法中發(fā)送MESSAGE_BLUETOOTH_SERVICE_CONNECTED 消息办成,在處理該消息時,做了下面三件事:
1搂漠、得到AdapterService返回的IBluetooth.aidl接口的實現(xiàn)類。
mBluetooth = IBluetooth.Stub.asInterface(service)
2.調(diào)用IBluetooth.aidl提供的接口注冊AdapterService的回調(diào)方法某弦。
這樣桐汤,不僅BluetoothManagerService可以通過aidl調(diào)用AdapterService中的方法而克,也實現(xiàn)了AdapterService可以回調(diào)BluetoothManagerService中的方法≌回調(diào)方法如下所示员萍,記住這個回調(diào)方法,后面會講到拣度。
mBluetooth.registerCallback(mBluetoothCallback)
3碎绎、第三件事就是調(diào)用IBluetooth.aidl提供的enable方法。下面就進入到AdapterService.java中抗果。
下面就進入了package/apps下:
首先看onBind方法筋帖,返回了一個對象mBinder。執(zhí)行其中的enable方法冤馏,
調(diào)用mAdapterStateMachine的sendMessage方法日麸,發(fā)送USER_TURN_ON消息。逮光。AdapterState.java是一個狀態(tài)機代箭,有以下幾種狀態(tài):
mOffState:關閉
mPendingCommandState:活動,打開中
mOnState:打開
初始狀態(tài)是mOffState涕刚。
發(fā)送消息后嗡综,在OffState狀態(tài)下處理消息,首先切換狀態(tài)到mPendingCommandState杜漠,然后調(diào)用adapterService.processStart()方法极景。
繼續(xù)回到adapterService。執(zhí)行如下代碼碑幅,啟動手機支持的所有profile戴陡,
手機支持的所有profile如下:
挨個啟動上面所有的服務。每個服務啟動之后都會調(diào)用adapterService中的notifyProfileServiceStateChanged方法沟涨。該方法中發(fā)送MESSAGE_PROFILE_SERVICE_STATE_CHANGED消息恤批。消息處理如下:
如果所有服務都起來之后,給狀態(tài)機AdapterState發(fā)送消息AdapterState.STARTED裹赴。
根據(jù)以上流程喜庞,現(xiàn)在狀態(tài)機在mPendingCommandState狀態(tài),在該狀態(tài)下處理STARTED消息棋返。代碼如下:
終于看到native方法延都。
對應的native方法在com_android_bluetooth_btservice_AdapterService.cpp中。調(diào)用了sBluetoothInterface結(jié)構(gòu)體中的enable方法睛竣。該結(jié)構(gòu)體的定義在bluetooth.h中晰房,具體實現(xiàn)在bluetooth.c中。后面的代碼這里不做具體分析。
回調(diào)主要使用
HAL_CBACK(bt_hal_cbacks, device_found_cb, num_properties, properties); HAL_CBACK就是一宏定義殊者,就是調(diào)用結(jié)構(gòu)體中對應的方法与境。
這里重點看一下一個bt_callbacks_t結(jié)構(gòu)體,定義在bluetooth.h中猖吴,如下
初始化在bluetooth.c中摔刁,初始化的流程。
回到AdapterService.java海蔽,在服務啟動時調(diào)用了initNative方法共屈。看下jni中的initNative方法:
還是sBluetoothInterface結(jié)構(gòu)體党窜,繼續(xù)看bluetooth.c文件拗引,可以看到init方法中將地址sBluetoothCallbacks賦值給bt_callbacks_t,也就是刑然,回調(diào)結(jié)構(gòu)體的地址指向了sBluetoothCallbacks寺擂,看下sBluetoothCallbacks的定義。任然在jni中定義泼掠。這樣在啟動AdapterService時將回調(diào)地址傳入了hal層怔软。
最后,在驅(qū)動層完成藍牙打開之后择镇,會執(zhí)行以下兩個回調(diào)方法:
adapter_properties_callback:返回手機藍牙設備的地址挡逼、名稱、UUID等腻豌。
adapter_state_change_callback:更新AdapterProperties中藍牙狀態(tài)家坎,發(fā)送廣播通知藍牙狀態(tài)變化。
具體分析下adapter_state_change_callback吝梅。對應的jni方法為:adapter_state_change_callback虱疏,方法執(zhí)行以下方法。
callbackEnv->CallVoidMethod(sJniCallbacksObj, method_stateChangeCallback, (jint)status);
也就是回調(diào)java層代碼:JniCallback.java文件中stateChangeCallback方法苏携。這時跳轉(zhuǎn)到AdapterState.java中做瞪,執(zhí)行stateChangeCallback()方法;發(fā)送了ENABLED_READY消息右冻。根據(jù)以上分析装蓬,這時狀態(tài)機還處于PendingCommandState,在該狀態(tài)下處理ENABLED_READY消息纱扭,
做下面兩個動作:狀態(tài)切換到mOnState牍帚;更新adapterProperties中的藍牙狀態(tài)信息;通知藍牙狀態(tài)變?yōu)榇蜷_乳蛾。具體看下notifyAdapterStateChange方法暗赶。主要是調(diào)用了adapterService類的方法鄙币。
adapterService.updateAdapterState(oldState, newState);
來到adapterService類。
可以看到蹂随,看是執(zhí)行該服務中注冊的回調(diào)方法爱榔。應該還能記得,之前在打開藍牙操作初期糙及,在BluetoothManagerService中注冊了回調(diào)方法。因此又跳轉(zhuǎn)到framework中筛欢,執(zhí)行回調(diào)方法浸锨。在該回調(diào)方法中,發(fā)送廣播通知藍牙狀態(tài)變化版姑。
2.4 總結(jié)
藍牙打開的流程到這里柱搜,藍牙打開從framework公共接口開始調(diào)用enable方法,執(zhí)行到bluetooth.apk中剥险,在該應用中通過jni注冊回調(diào)方法和調(diào)用hal層打開藍牙方法聪蘸,在驅(qū)動層完成藍牙上電等操作后,通過hal-jni回調(diào)到應用層中表制,應用通過aidl回調(diào)通知framework藍牙狀態(tài)變化健爬,framework發(fā)送廣播通知大家藍牙打開。
packages/apps/Bluetooth/src/com/android/bluetooth/btservice/RemoteDevices.java
packages/apps/Settings/src/com/android/settings/Bluetooth/*
BluetoothSettings.java中的startScanning命令么介,開始搜索娜遵。
如果a2dp沒有在播放,就調(diào)用BluetoothAdapter.java中的startDiscovery()方法壤短。
然后又回到AdapterService中设拟,調(diào)用startDiscovery方法。在該方法中直接進入到jni層久脯。
在jni層的函數(shù)中執(zhí)行如下語句纳胧,依然是該結(jié)構(gòu)體。
int ret = sBluetoothInterface->start_discovery();
具體的底層搜索方法暫不往下追蹤帘撰。驅(qū)動層完成搜索之后跑慕,返回狀態(tài),根據(jù)返回的消息進行處理骡和∠嗔蓿回調(diào)消息分如下幾種:包括搜索結(jié)果返回消息、搜索完成消息慰于、搜索取消等钮科。
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
當收到搜索結(jié)果放回消息之后,會執(zhí)行以下回調(diào)方法婆赠。
其中后面兩個參數(shù):設備屬性個數(shù)和設備屬性绵脯。其中設備屬性包括:地址佳励、名稱、信號強度等屬性蛆挫。根據(jù)上面所講的回調(diào)方法初始化赃承,直接找到jni層的對應回調(diào)方法,可以看到會先后調(diào)用以下兩個方法悴侵。
其中devicePropertyChangedCallback方法更新RemoteDevice類中的變量值瞧剖。
deviceFoundCallback方法發(fā)送BluetoothDevice.ACTION_FOUND廣播,通知setting中要更新界面顯示該設備可免。
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
在setting中點擊設備之后開始進行配對抓于。調(diào)用BluetoothDevice的createBond方法,走到AdapterService.java中的createBond方法浇借。驅(qū)動BondStateMachine中的狀態(tài)從StableState到
PendingCommandState捉撮。然后調(diào)用jni層createBondNative方法。又來到hal層接口sBluetoothInterface:
sBluetoothInterface->create_bond((bt_bdaddr_t *)addr);
同樣妇垢,在底層完成配對之后進行回調(diào):
找到對應的回調(diào)方法巾遭,JniCallback.java中的
void bondStateChangeCallback(int status, byte[] address, int newState) {
mBondStateMachine.bondStateChangeCallback(status, address, newState);
}
只有opp的彈框是bluetooth里,其他都是setting中彈框闯估。
點擊用藍牙分享文件后灼舍,會調(diào)用BluetoothOppLauncherActivity.java,其中會判斷當前藍牙是否打開睬愤,如果沒打開則進入BluetoothOppBtEnableActivity.java打開藍牙片仿,如果已經(jīng)打開,則直接進入BluetoothDevicePicker.java選擇傳輸文件設備選擇尤辱。
藍牙開啟后會啟動BluetoothMapService.java
在BluetoothMapService.java調(diào)用了BluetoothMapMasInstance.java的startRfcommSocketListener()方法砂豌,監(jiān)聽rfcomm端的連接請求,如果有連接請求光督,調(diào)用BluetoothMapService 的 onConnect()方法阳距,在該方法里發(fā)送廣播到setting中,setting彈框结借,用戶確認后發(fā)送廣播ACTION_CONNECTION_ACCESS_REPLY通知BluetoothMapService筐摘,BluetoothMapService收到廣播后調(diào)用onConnectHandler方法,調(diào)用startObexServerSession方法船老,啟動Obex傳輸通道咖熟。
手機側(cè)主動改變狀態(tài)。注冊了一個RemoteControllerWeak(RemoteController)柳畔,當手機端的播放器暫停馍管、快進、快退薪韩、切歌等操作后确沸,會調(diào)用遠程控制接口更新播放狀態(tài)捌锭、歌曲信息。mTrackChangedNT罗捎、mPlayStatusChangedNT观谦、mPlayPosChangedNT三個變量的值決定是否會通知對端進行同步;這三個值有jni回調(diào)改變桨菜,即對端回調(diào)改變豁状。
對端主動改變狀態(tài):1)快進、快退底層有回調(diào)handlePassthroughCmd倒得,來通知avrcp實時更新進度條替蔬,并同步給對端。部分車載會上報快進屎暇、快退的keycode給手機端,播放器利用RemoteController更新狀態(tài)驻粟。2)播放根悼、暫停,對端上報keycode蜀撑,播放器RemoteController控制avrcp中狀態(tài)切換
類似map挤巡,連接后彈框都是廣播給setting彈框
之前的audiopath比較復雜,要到DSP里面去硬解碼】崧螅現(xiàn)在比較簡單了矿卑,從驅(qū)動角度看,收到AF寫下來的PCM數(shù)據(jù)后沃饶,經(jīng)協(xié)議棧SBC編碼后經(jīng)HCI接口寫入到藍牙芯片母廷,然后就發(fā)出去了。
SBC編碼是針對藍牙設備的一種音頻編碼方式糊肤,壓縮率中等琴昆,但是cpu消耗低。電話對應HFP profile馆揉,音樂對應Profile业舍。電話使用的是同步鏈路SCO,音樂時異步鏈路ACL升酣,使用A2DP profile舷暮。另外還有其它profile,傳問題噩茄,獲取電話本下面,短信同步等。
使用A2DP時巢墅,先是進行音樂的解碼诸狭,然后再把解碼后的PCM進行SBC編碼券膀。A2DP支持下行audio編碼采樣率范圍為8k-48k。在高通的大多數(shù)方案里面驯遇,SBC編碼是在DSP里做的芹彬。
HFP,有兩個角色AG和HF叉庐,正常情況下手機作為AG舒帮,耳機作為HF。但是手機代碼中也有HF部分的代碼
手機藍牙芯片是三合一的陡叠,包括BT玩郊,F(xiàn)M和WLAN,使用一根天線枉阵。藍牙耳機和藍牙模塊之間通過AT命令進行通信译红,分為master和slave,誰先連對方誰就是master兴溜。藍牙功耗待機1mA左右侦厚,傳文件要100多mA,聽音樂60左右拙徽,打電話30刨沦。
--------------------------------------------------------
轉(zhuǎn)自:https://blog.csdn.net/pashanhu6402/article/details/80183495