藍牙流程介紹

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藍牙結(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ī)范

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對象凹炸,并且用該對象創(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中。后面的代碼這里不做具體分析。

2.3 底層回調(diào)流程

回調(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ā)送廣播通知大家藍牙打開。

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沒有在播放,就調(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中要更新界面顯示該設備可免。

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中點擊設備之后開始進行配對抓于。調(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);

}

5 Opp文件傳輸

只有opp的彈框是bluetooth里,其他都是setting中彈框闯估。

5.1 發(fā)送文件

點擊用藍牙分享文件后灼舍,會調(diào)用BluetoothOppLauncherActivity.java,其中會判斷當前藍牙是否打開睬愤,如果沒打開則進入BluetoothOppBtEnableActivity.java打開藍牙片仿,如果已經(jīng)打開,則直接進入BluetoothDevicePicker.java選擇傳輸文件設備選擇尤辱。

6 Map消息訪問profile

藍牙開啟后會啟動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傳輸通道咖熟。

7 AVRCP

手機側(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)切換

8 Pbap

類似map挤巡,連接后彈框都是廣播給setting彈框

9 功耗

之前的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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市膘怕,隨后出現(xiàn)的幾起案子想诅,更是在濱河造成了極大的恐慌,老刑警劉巖岛心,帶你破解...
    沈念sama閱讀 211,639評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件来破,死亡現(xiàn)場離奇詭異,居然都是意外死亡忘古,警方通過查閱死者的電腦和手機讳癌,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,277評論 3 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來存皂,“玉大人晌坤,你說我怎么就攤上這事〉┐” “怎么了骤菠?”我有些...
    開封第一講書人閱讀 157,221評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長疤孕。 經(jīng)常有香客問我商乎,道長,這世上最難降的妖魔是什么祭阀? 我笑而不...
    開封第一講書人閱讀 56,474評論 1 283
  • 正文 為了忘掉前任鹉戚,我火速辦了婚禮鲜戒,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘抹凳。我一直安慰自己遏餐,他們只是感情好,可當我...
    茶點故事閱讀 65,570評論 6 386
  • 文/花漫 我一把揭開白布赢底。 她就那樣靜靜地躺著失都,像睡著了一般。 火紅的嫁衣襯著肌膚如雪幸冻。 梳的紋絲不亂的頭發(fā)上粹庞,一...
    開封第一講書人閱讀 49,816評論 1 290
  • 那天,我揣著相機與錄音洽损,去河邊找鬼庞溜。 笑死,一個胖子當著我的面吹牛碑定,可吹牛的內(nèi)容都是我干的强缘。 我是一名探鬼主播,決...
    沈念sama閱讀 38,957評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼不傅,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了赏胚?” 一聲冷哼從身側(cè)響起访娶,我...
    開封第一講書人閱讀 37,718評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎觉阅,沒想到半個月后崖疤,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,176評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡典勇,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,511評論 2 327
  • 正文 我和宋清朗相戀三年劫哼,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片割笙。...
    茶點故事閱讀 38,646評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡权烧,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出伤溉,到底是詐尸還是另有隱情般码,我是刑警寧澤,帶...
    沈念sama閱讀 34,322評論 4 330
  • 正文 年R本政府宣布乱顾,位于F島的核電站板祝,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏走净。R本人自食惡果不足惜券时,卻給世界環(huán)境...
    茶點故事閱讀 39,934評論 3 313
  • 文/蒙蒙 一孤里、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧橘洞,春花似錦捌袜、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,755評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至抛虏,卻和暖如春博其,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背迂猴。 一陣腳步聲響...
    開封第一講書人閱讀 31,987評論 1 266
  • 我被黑心中介騙來泰國打工慕淡, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人沸毁。 一個月前我還...
    沈念sama閱讀 46,358評論 2 360
  • 正文 我出身青樓峰髓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親息尺。 傳聞我的和親對象是個殘疾皇子携兵,可洞房花燭夜當晚...
    茶點故事閱讀 43,514評論 2 348

推薦閱讀更多精彩內(nèi)容