Android 藍(lán)牙框架

一、前言

本文側(cè)重點(diǎn):Android中藍(lán)牙代碼結(jié)構(gòu)分析尿招。
代碼來(lái)源于Android P踊餐,本文相關(guān)代碼:
client:
frameworks/base/core/java/android/bluetooth/*
system/bt/binder/android/bluetooth/**.aidl
servie:
framework/base/services/core/java/com/android/server/BluetoothService.java
framework/base/services/core/java/com/android/server/BluetoothManagerService.java
bluetooth:
package/app/bluetooth
(上面是aosp源碼提供的藍(lán)牙實(shí)現(xiàn)乱豆。而芯片廠商提供的代碼一般這部分是沒(méi)有源碼的伶棒,比如mtkbluetooth.apk直接替換此apk。但aosp提供的源碼供我們學(xué)習(xí)還是可以的项戴。)
settingslib:
vendor/mediatek/proprietary/packages/apps/SettingsLib/src/com/android/settingslib/bluetooth/

(SettingsLib原生frameworks/base/packages/SettingsLib也有形帮,上面是MTK定制,主要區(qū)別是對(duì)協(xié)議的修改添加一些支持等)

上面四個(gè)部分是藍(lán)牙核心的地方周叮。對(duì)于系統(tǒng)的應(yīng)用從AndroidP開(kāi)始辩撑。AOSP已經(jīng)原生支持對(duì)藍(lán)牙的各種接口了。只要芯片廠商對(duì)接好系統(tǒng)藍(lán)牙接口我們就可以依賴原生接口開(kāi)發(fā)自己想要的應(yīng)用app仿耽,下面是功能應(yīng)用的表格:

功能 依賴項(xiàng)
Diar 通話相關(guān)合冀,來(lái)去電走Android原生telecom流程。聯(lián)系人/通話記錄依賴原生contactsprovider
music 音樂(lè)相關(guān)项贺,走原生Mediasession
settings 藍(lán)牙設(shè)置相關(guān)君躺,用settingsLib控制,開(kāi)關(guān)連接等
其他 其他應(yīng)用依賴于Android自身支持的協(xié)議(profile)比如GATT低功耗藍(lán)牙开缎,OPP文件傳輸棕叫,等等

注:
1、本文以分析整體為主奕删。讀者需要對(duì)framework中service/client結(jié)構(gòu)熟悉(此文有介紹這種結(jié)構(gòu):PackageManagerService服務(wù)框架詳解)俺泣。另外建議閱讀時(shí)去翻翻對(duì)應(yīng)路徑下的源碼,便于理解。
2伏钠、本文以整體框架講解的思想來(lái)闡述侮邀。特殊流程會(huì)源碼講解,講解時(shí)只列出源碼關(guān)鍵代碼行贝润。大部分只總結(jié)它的作用。需要讀者自行去結(jié)合源碼理解铝宵。

二打掘、功能簡(jiǎn)單介紹

首先藍(lán)牙服務(wù)和AMS、PMS等系統(tǒng)眾多服務(wù)一樣鹏秋,也是service/client結(jié)構(gòu)尊蚁。不理解S/C結(jié)構(gòu)的同學(xué)可以直接理解為普通的API調(diào)用,直接調(diào)用最終在BluetoothManagerService.java代碼里侣夷,方法名大部分都一樣横朋。

2.1、四部分(client百拓、service琴锭、bluetooth、settinglib)

藍(lán)牙的代碼主要分為標(biāo)題的四個(gè)部分

2.1.1衙传、client

客戶端主要代碼是BluetoothAdapter决帖,我們平時(shí)開(kāi)發(fā)時(shí)都是通過(guò)操作BluetoothAdapter的公開(kāi)api來(lái)實(shí)現(xiàn)我們的功能。
除開(kāi)BluetoothAdapter起到核心作用之外在com.android.bluetooth下還默認(rèn)提供一些默認(rèn)協(xié)議API級(jí)的支持蓖捶。這些協(xié)議都是一個(gè)獨(dú)立的profile實(shí)現(xiàn)地回。這些profile使我們可以控制藍(lán)牙工作于我們想要的場(chǎng)景下。通常這部分三方apk使用較多俊鱼。

名稱 簡(jiǎn)單介紹
A2dp 音頻
Gatt 低功耗
Headset 藍(lán)牙耳機(jī)
Health 健康
Socket 面向連接刻像,套接字,基于RFCOMM

2.2.2并闲、service

代碼:BluetoothManagerService.java
service管理:
BluetoothManagerService里主要是framework層實(shí)現(xiàn)藍(lán)牙功能的地方细睡。我們從BluetoothAdapter調(diào)用方法都會(huì)調(diào)用到BluetoothManagerService里,而BluetoothManagerService里的大部分實(shí)現(xiàn)又是通過(guò)綁定bluetooth apk里的service(AdapterService)來(lái)實(shí)現(xiàn)帝火。這樣BluetoothManagerService既起到了統(tǒng)一framework藍(lán)牙實(shí)現(xiàn)的地方纹冤,又讓Bluetooth apk可以有豐富的profile具體功能實(shí)現(xiàn)。
Profile理解:
一個(gè)藍(lán)牙硬件模塊根據(jù)藍(lán)牙規(guī)范(比如藍(lán)牙4.0)购公。會(huì)默認(rèn)實(shí)現(xiàn)很多自帶的協(xié)議萌京。由于制定協(xié)議的人多個(gè)組等其他原因。藍(lán)牙規(guī)范是有很多個(gè)細(xì)分的協(xié)議協(xié)同工作宏浩≈校可以理解為一種通信規(guī)范。一個(gè)標(biāo)準(zhǔn)的藍(lán)牙模塊肯定得把藍(lán)牙規(guī)范里的協(xié)議都實(shí)現(xiàn)比庄。而Profile的存在的意義就是求妹。不管你標(biāo)準(zhǔn)有多少個(gè)協(xié)議乏盐,我只要我想要的功能,別的我不管制恍。比如A2dp音頻協(xié)議父能。我只需要藍(lán)牙工作于A2dp就可以了。當(dāng)然A2dp可能是基于其中某幾個(gè)協(xié)議上的協(xié)議净神。但是別的協(xié)議它沒(méi)有何吝。用JavaScript的思想來(lái)理解Profile,它就是一個(gè)切面鹃唯。

2.2.3爱榕、bluetooth

bluetooth是藍(lán)牙協(xié)議具體實(shí)現(xiàn)的地方。比如BluetoothAdapter#enable打開(kāi)藍(lán)牙的時(shí)候坡慌,跟蹤代碼最后的調(diào)用就會(huì)跟蹤到bluetooth apk里黔酥。而打開(kāi)操作就在bluetooth中的AdapterService。這個(gè)是service就是藍(lán)牙功能的服務(wù)洪橘。在BluetoothManagerService中會(huì)綁定AdapterService跪者,拿到服務(wù)后,就間接提供給client中的BluetoothAdapter API使用熄求。下面用連個(gè)截圖來(lái)展示它的豐富的實(shí)現(xiàn)

bluetooth.png

bluetooth apk由于是具體的實(shí)現(xiàn)坑夯,所以它會(huì)實(shí)現(xiàn)所有的協(xié)議。
除開(kāi)client中提供的profile抡四,還有settingslib中系統(tǒng)藍(lán)牙操作功能實(shí)現(xiàn)的Profile柜蜈。這些豐富的profile會(huì)在下一小節(jié)列出。

2.2.4指巡、settingslib

settingsLib和其他三個(gè)部分是相對(duì)而言比較獨(dú)立的一個(gè)部分淑履。因?yàn)樗皇欠庋b操作。以便settings可以更方便的控制管理
settingslib主要是服務(wù)系統(tǒng)app:settings使用藻雪,編譯時(shí)一般也是編譯settings的時(shí)候一起編譯settingslib秘噪。
只有系統(tǒng)級(jí)權(quán)限(集成到系統(tǒng)中,system/app勉耀、framework等)才可以調(diào)用settingslib指煎,普通三方應(yīng)用開(kāi)發(fā)者無(wú)法使用
settingslib中藍(lán)牙代碼相當(dāng)于也是操作BluetoothAdapter,BluetoothAdapter間接調(diào)用BluetoothManagerService來(lái)實(shí)現(xiàn)功能.
在SettingsLib\src\com\android\settingslib\bluetooth中我們還能看到像com.android.bluetooth路徑下那些協(xié)議之外的一些協(xié)議

名稱 簡(jiǎn)單介紹 名稱 簡(jiǎn)單介紹
A2dp 音頻 Headset 藍(lán)牙耳機(jī)
HearingAid 助聽(tīng)器 Hfp 免提
Hid 人機(jī)接口設(shè)備 Map 信息訪問(wèn)
Opp 對(duì)象推送 Pan 個(gè)人局域網(wǎng)
Pbap 電話薄 Sap 會(huì)話通知

看到這些協(xié)議便斥,settingslib服務(wù)于系統(tǒng)就很好理解了至壤。一個(gè)手機(jī)連上藍(lán)牙。那么手機(jī)設(shè)置支持藍(lán)牙相關(guān)的操作也就是這些協(xié)議支持的功能

三枢纠、詳解四大部分(client像街、service、bluetooth、settinglib)

文章第二段對(duì)Android藍(lán)牙框架代碼已經(jīng)有了一個(gè)簡(jiǎn)單的介紹镰绎。就是這四個(gè)部分代碼支撐著藍(lán)牙的各種功能脓斩。接下來(lái)將詳細(xì)介紹四個(gè)部分比較核心的內(nèi)容。

3.1畴栖、BluetoothAdapter詳細(xì)介紹(client)

BluetoothAdapter部分主要是api使用随静,所以這部分以表格方式列出信息方便查閱
第一個(gè)表是BluetoothAdapter定義的一些狀態(tài)和通知:

作用類型 關(guān)鍵字 介紹
開(kāi)關(guān)通知 ACTION_STATE_CHANGED 上次狀態(tài)和當(dāng)前狀態(tài)
開(kāi)關(guān)狀態(tài)定義 AdapterState 描述當(dāng)前藍(lán)牙狀態(tài)
請(qǐng)求掃描 ACTION_REQUEST_DISCOVERABLE 請(qǐng)求掃描,默認(rèn)120秒吗讶,可帶時(shí)間參數(shù) activity#resulet
請(qǐng)求掃描 ACTION_REQUEST_BLE_SCAN_ALWAYS_AVAILABLE 一直允許掃描 activity#resulet
請(qǐng)求打開(kāi)/關(guān)閉 ACTION_REQUEST_ENABLE燎猛、ACTION_REQUEST_DISABLE 請(qǐng)求打開(kāi)/關(guān)閉activity#resulet
掃描狀態(tài)通知 ACTION_SCAN_MODE_CHANGED 上次狀態(tài)和當(dāng)前狀態(tài)
掃描狀態(tài)定義 ScanMode 描述掃描狀態(tài)
掃描開(kāi)始/結(jié)束通知 ACTION_DISCOVERY_STARTED、ACTION_DISCOVERY_FINISHED
名字改變通知 ACTION_LOCAL_NAME_CHANGED 帶名字參數(shù)
連接狀態(tài)通知 ACTION_CONNECTION_STATE_CHANGED 帶當(dāng)前和上次狀態(tài)
LE下?tīng)顟B(tài)通知 ACTION_BLE_STATE_CHANGED 藍(lán)牙只在低功耗模式時(shí)狀態(tài)變化
mac地址變化 ACTION_BLUETOOTH_ADDRESS_CHANGED 帶參數(shù)
連接類型 ACTION_BLE_ACL_CONNECTED
斷開(kāi)連接類型 ACTION_BLE_ACL_CONNECTED

上面這些豐富的廣播通知是在bluetooth apk里的實(shí)現(xiàn)的关翎。bluetooth中的btservice中收到狀態(tài)的時(shí)候直接發(fā)出廣播

第二個(gè)表是BluetoothAdapter.java內(nèi)部方法(方法只是提及,不包括所有鸠信,類似或者不重要的省略):

方法 作用 方法 作用
getDefaultAdapter 拿對(duì)象 getRemoteDevice 遠(yuǎn)端設(shè)備
getBluetoothLeAdvertiser LE廣播數(shù)據(jù) getPeriodicAdvertisingManager LE注冊(cè)管理
getBluetoothLeScanner 掃描 isEnabled 開(kāi)
getState 狀態(tài) getLeState LE狀態(tài)
enable 打開(kāi) getAddress 地址
setName 名字 factoryReset 出廠設(shè)置
getUuids uuid getBluetoothClass 遠(yuǎn)端設(shè)備信息判斷設(shè)備類型是否提供某個(gè)service等
setScanMode 掃描模式 setDiscoverableTimeout 超時(shí)時(shí)間
cancelDiscovery 取消 isDiscovering 是否掃描
isLe*** LE設(shè)備功能支持判斷 getMaxConnectedAudioDevices 最大audio設(shè)備數(shù)
requestControllerActivityEnergyInfo 獲取藍(lán)牙信息比如電量 getBondedDevices 已配對(duì)設(shè)備
getSupportedProfiles 支持的協(xié)議 getConnectionState 連接狀態(tài)
getProfileConnectionState 協(xié)議連接狀態(tài) listen*** 創(chuàng)建service監(jiān)聽(tīng)例如開(kāi)氣socket服務(wù)
getProfileProxy 客戶端拿到服務(wù)比如pbap closeProfileProxy 關(guān)閉連接
enableNoAutoConnect 打開(kāi) checkBluetoothAddress 有效地址判斷
getBluetoothManager 獲得bluetoothmanagerservice getBluetoothService 獲得藍(lán)牙服務(wù)
startLeScan LE開(kāi)始掃描 stopLeScan 停止le掃描

BluetoothAdapter小結(jié)
1纵寝、BluetoothAdapter的重要信息上面基本都列出來(lái)了。除了常規(guī)的開(kāi)關(guān)監(jiān)聽(tīng)等操作外星立。還有很多掃描連接狀態(tài)等得廣播通知發(fā)送出來(lái)爽茴。
2、我們的apk客戶端想要和某個(gè)profile服務(wù)綁定時(shí)绰垂,通過(guò)getProfileProxy來(lái)拿到服務(wù)和監(jiān)聽(tīng)
3室奏、低功耗LE設(shè)備也提供了一些操作方法

3.2、BluetoothManagerService詳細(xì)介紹(service)

BluetoothManagerService功能實(shí)現(xiàn)比較分散劲装,下面以講解比較重要的幾個(gè)代碼流程邏輯為主胧沫。
BluetoothManagerService這部分主要是功能的詳細(xì)實(shí)現(xiàn)。而BluetoothManagerService和其他系統(tǒng)service不太一樣占业。它這里的實(shí)現(xiàn)也只是表面封裝一下绒怨。具體的實(shí)現(xiàn)是通過(guò)綁定bluetooth apk里的AdapterService,然后通過(guò)AdapterService來(lái)實(shí)現(xiàn)谦疾。下面我們看下怎么調(diào)用到AdapterService的南蹂。

3.2.1、系統(tǒng)api調(diào)用流程

BluetoothManagerService調(diào)用到package/app/bluetooth
BluetoothAdapter->BluetoothManagerService->AdapterService(bluetooth apk)上面client部分列出的方法大部分都是這個(gè)操作流程念恍,走到bluetooth里的具體實(shí)現(xiàn)六剥。

查看BluetoothAdapter調(diào)用邏輯,和其他系統(tǒng)api一樣峰伙,藍(lán)牙也是S/C結(jié)構(gòu)疗疟。那么具體實(shí)現(xiàn)就都會(huì)集中到BluetoothManagerService。查看BluetoothManagerService代碼我們很容發(fā)現(xiàn)里面的詳細(xì)實(shí)現(xiàn)主要有兩個(gè)間接調(diào)用mManagerService和mBluetooth 瞳氓。我們跟一下這兩個(gè)對(duì)象秃嗜。
BluetoothManagerService.java代碼片段:

IBluetoothManager mManagerService =  IBluetoothManager.Stub.asInterface(ServiceManager.getService(BLUETOOTH_MANAGER_SERVICE));
 private void handleEnable(boolean quietMode) {
       ...
                Intent i = new Intent(IBluetooth.class.getName());
                if (!doBind(i, mConnection, Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT,
                        UserHandle.CURRENT)) {
                   ...
                }
private class BluetoothServiceConnection implements ServiceConnection {
        public void onServiceConnected(ComponentName componentName, IBinder service) {
            ...
            msg.obj = service;
            mHandler.sendMessage(msg);
        }
mBluetooth = IBluetooth.Stub.asInterface(Binder.allowBlocking(service));  

mManagerService很好理解就是綁定到了我們的BluetoothManagerService服務(wù)。
mManagerService在打開(kāi)藍(lán)牙的時(shí)候會(huì)間接調(diào)用到handleEnable方法,handleEnable的dobind會(huì)綁定BluetoothService,回調(diào)到BluetoothServiceConnection方法中把service賦值給mBluetooth锅锨,這樣我們就可以拿到Bluetooth app里的service(AdapterService)進(jìn)行操作了叽赊。

3.2.2、BluetoothAdapter和Bluetooth apk其他協(xié)議綁定調(diào)用

這個(gè)流程和BluetoothManagerService沒(méi)什么關(guān)系,但是和3.2.1極其相似,所以放在這里講恨搓。
普通三方apk可以通過(guò)BluetoothAdapter#getProfileProxy來(lái)拿到協(xié)議翰绊,并通過(guò)協(xié)議進(jìn)行具體操作。操作實(shí)際也會(huì)操作到Bluetooth apk里惕味。我們以settingslib連接使用profile來(lái)講解。整體流程大致如下:
settingslib->settingslib#setBluetoothStateOn->bluetoothadater#getProfileProxy->bluetooth apk profile service
1、settinglib中LocalBluetoothAdapter打開(kāi)藍(lán)牙
首先除了默認(rèn)的BluetoothAdapter#enable可以打開(kāi)外葛家,settinglib中LocalBluetoothAdapter#enable也可以打開(kāi),打開(kāi)時(shí)代碼會(huì)走到LocalBluetoothProfileManager#setBluetoothStateOn泌类。我們以HidProfile為代表來(lái)講

// Called from LocalBluetoothAdapter when state changes to ON
    void setBluetoothStateOn() {
        if (mHidProfile == null) {
        mHidProfile = new HidProfile(mContext, mLocalAdapter, mDeviceManager, this);
        addProfile(mHidProfile, HidProfile.NAME,
                BluetoothHidHost.ACTION_CONNECTION_STATE_CHANGED);
       }

2癞谒、HidProfile拿到bluetooth apk中的HidProfile服務(wù)

public class HidProfile implements LocalBluetoothProfile {
   public void onServiceConnected(int profile, BluetoothProfile proxy) {
            if (V) Log.d(TAG,"Bluetooth service connected");
            mService = (BluetoothHidHost) proxy;
          ....
     HidProfile(Context context, LocalBluetoothAdapter adapter,
        CachedBluetoothDeviceManager deviceManager,
        LocalBluetoothProfileManager profileManager) {
        ...
        adapter.getProfileProxy(context, new HidHostServiceListener(),
                BluetoothProfile.HID_HOST);
    }

這里的HidProfile代碼在settinglib中,創(chuàng)建時(shí)核心的調(diào)用到了adapter.getProfileProxy刃榨。這里就是framework層通過(guò)BluetoothAdapter拿到bluetooth apk中的profile service核心邏輯
BluetoothAdapter#getProfileProxy

public boolean getProfileProxy(Context context, BluetoothProfile.ServiceListener listener,
            int profile) {
        ....
        if (profile == BluetoothProfile.HEADSET) {
            BluetoothHeadset headset = new BluetoothHeadset(context, listener);
            return true;
        } 
        ....
        else if (profile == BluetoothProfile.HID_HOST) {
            BluetoothHidHost iDev = new BluetoothHidHost(context, listener);
            return true;
        } 

這里又會(huì)新創(chuàng)建一個(gè)HID的profile對(duì)象BluetoothHidHost弹砚。(這里容易和settingslib中的HidProfile混淆,這個(gè)HID還好名字有區(qū)別枢希,別的profile名字極其類似桌吃。)BluetoothHidHost在路徑frameworks\base\core\java\android\bluetooth

 private final ServiceConnection mConnection = new ServiceConnection() {
        public void onServiceConnected(ComponentName className, IBinder service) {
            if (DBG) Log.d(TAG, "Proxy object connected");
            mService = IBluetoothHealth.Stub.asInterface(Binder.allowBlocking(service));

            if (mServiceListener != null) {
                mServiceListener.onServiceConnected(BluetoothProfile.HEALTH, BluetoothHealth.this);
            }
        }
      ...
BluetoothHidHost(Context context, ServiceListener l) {
        ...
        doBind();
    }
boolean doBind() {
        Intent intent = new Intent(IBluetoothHidHost.class.getName());
        ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
        intent.setComponent(comp);
        if (comp == null || !mContext.bindServiceAsUser(intent, mConnection, 0,
                mContext.getUser())) {
            Log.e(TAG, "Could not bind to Bluetooth HID Service with " + intent);
            return false;
        }
        return true;
    }

dobind時(shí),就和上面講解的API調(diào)用流程比較類似苞轿,綁定服務(wù)茅诱,并把bluetooth apk里的service,回調(diào)給mConnection搬卒。這樣BluetoothHidHost就綁定了bluetooth apk里的HIDProfile service 并獲得代理對(duì)象让簿。在mConnection中,又通過(guò)剛才HidProfile 傳入的listenner回調(diào)傳回service秀睛,讓HidProfile 也擁有了Bluetooth apk中的這個(gè)service尔当。
3、流程概述
<1>蹂安、1,2流程下來(lái)椭迎。settinglib中打開(kāi)時(shí)就會(huì)創(chuàng)建支持的profile,這些profile創(chuàng)建的時(shí)候田盈,都大同小異的讓BluetoothAdapter也創(chuàng)一個(gè)名字類似的profile畜号,讓兩個(gè)profile都拿到bluetooth apk中對(duì)應(yīng)協(xié)議的service。當(dāng)profile拿到service了允瞧,有了bluetooth apk具體的實(shí)現(xiàn)了简软,就能調(diào)用到具體的功能上了蛮拔。
<2>、注意這里的service和協(xié)議的service/client中的service要區(qū)分開(kāi)痹升。client也是在要bluetooth apk運(yùn)行一個(gè)服務(wù)來(lái)供系統(tǒng)使用建炫。
<3>、三方應(yīng)用可以BluetoothAdapter#getProfileProxy來(lái)拿到profile操作疼蛾。一般profile實(shí)現(xiàn)的方法也不多肛跌,只能調(diào)用一些簡(jiǎn)單的方法。有哪些公開(kāi)api直接打開(kāi)某個(gè)profile就能看到

BluetoothManagerService小結(jié)
由于service的特性察郁,就是各個(gè)功能的具體實(shí)現(xiàn)衍慎。所以對(duì)于service的分析一般都是流程為主。BluetoothManagerService的功能和系統(tǒng)其他服務(wù)比相對(duì)比較簡(jiǎn)單皮钠∥壤Γ基本就是綁定bluetoothapk 的service,具體的實(shí)現(xiàn)還是都在Bluetooth apk里麦轰。

3.3乔夯、bluetooth apk

這部分代碼芯片廠商一般有自己的私有定制,未開(kāi)放源碼原朝,學(xué)習(xí)這部分參考AOSP源碼package/app/bluetooth
Bluetooth apk里就是我們藍(lán)牙功能具體的實(shí)現(xiàn)了驯嘱。常規(guī)打開(kāi)關(guān)閉功能在AdapterService入口實(shí)現(xiàn)镶苞。這些方法最后跟蹤都會(huì)跟蹤到native方法上喳坠。由于方法流程很多,這里以打開(kāi)流程來(lái)舉例介紹

3.3.1茂蚓、AdapterService#enable

enable就是打開(kāi)的入口壕鹉,我們跟一下打開(kāi)流程
1、狀態(tài)機(jī)開(kāi)始工作

private AdapterState mAdapterStateMachine;
 public synchronized boolean enable(boolean quietMode) {
        ...
        mAdapterStateMachine.sendMessage(AdapterState.BLE_TURN_ON);
    }

AdapterState.java代碼片段
    private TurningOnState mTurningOnState = new TurningOnState();
    private TurningBleOnState mTurningBleOnState = new TurningBleOnState();
    private TurningOffState mTurningOffState = new TurningOffState();
    private TurningBleOffState mTurningBleOffState = new TurningBleOffState();
    private OnState mOnState = new OnState();
    private OffState mOffState = new OffState();
    private BleOnState mBleOnState = new BleOnState();
private AdapterState(AdapterService service) {
        super(TAG);
        addState(mOnState);
        addState(mBleOnState);
        addState(mOffState);
        addState(mTurningOnState);
        addState(mTurningOffState);
        addState(mTurningBleOnState);
        addState(mTurningBleOffState);
        mAdapterService = service;
        setInitialState(mOffState);
    }

打開(kāi)的工作交給了AdapterState聋涨。AdapterState 是一個(gè)狀態(tài)機(jī)晾浴,狀態(tài)機(jī)改變狀態(tài)時(shí)就會(huì)執(zhí)行類的一些行為。Android的狀態(tài)機(jī)制一般用于復(fù)雜狀態(tài)+復(fù)雜操作牍白。這里你可以簡(jiǎn)單理解為狀態(tài)切一下就會(huì)去執(zhí)行對(duì)應(yīng)操作脊凰。
構(gòu)造函數(shù)默認(rèn)是mOffState,收到BLE_TURN_ON消息茂腥。那么第一個(gè)地方就是OffState的processMessage處理BLE_TURN_ON狸涌,消息也是再直接傳遞到TurningBleOnState

 private class OffState extends BaseAdapterState {
        ...
        @Override
        public boolean processMessage(Message msg) {
            switch (msg.what) {
                case BLE_TURN_ON:
                    transitionTo(mTurningBleOnState);
                    break;
        }
    }

2、把打開(kāi)消息傳給GattService

 private class TurningBleOnState extends BaseAdapterState {
        ...
        @Override
        public void enter() {
            super.enter();
            sendMessageDelayed(BLE_START_TIMEOUT, BLE_START_TIMEOUT_DELAY);
            mAdapterService.bringUpBle();
        }
      ...
        @Override
        public boolean processMessage(Message msg) {
            switch (msg.what) {
                case BLE_STARTED:
                    transitionTo(mBleOnState);
                    break;

    void bringUpBle() {
        ...
        //Start Gatt service
        setProfileServiceState(GattService.class, BluetoothAdapter.STATE_ON);
    }

  class AdapterServiceHandler extends Handler {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case MESSAGE_PROFILE_SERVICE_STATE_CHANGED:
                    processProfileServiceStateChanged((ProfileService) msg.obj, msg.arg1);
                    break;

3最岗、GattService打開(kāi)藍(lán)牙

private void processProfileServiceStateChanged(ProfileService profile, int state) {
            switch (state) {
                case BluetoothAdapter.STATE_ON:
                    ...
                    if (GattService.class.getSimpleName().equals(profile.getName())) {
                        enableNativeWithGuestFlag();
                    } 
private void enableNativeWithGuestFlag() {
        boolean isGuest = UserManager.get(this).isGuestUser();
        if (!enableNative(isGuest)) {
            Log.e(TAG, "enableNative() returned false");
        }
    }

這樣就調(diào)用到了底層實(shí)現(xiàn)的native方法

3.3.2帕胆、其他協(xié)議啟動(dòng)

上面3.3.1講解BluetoothAdapter#enable時(shí),BluetoothManagerService代碼從BluetoothManagerService調(diào)用到bluetooh apk的Adapterservice最后一步BluetoothServiceConnection 回調(diào)MESSAGE_BLUETOOTH_SERVICE_CONNECTED信息般渡,代碼從這里接著開(kāi)始懒豹。
1芙盘、framwork調(diào)用到bluetooth apk里

private class BluetoothHandler extends Handler {
        ...
        @Override
        public void handleMessage(Message msg) {
case MESSAGE_BLUETOOTH_SERVICE_CONNECTED: {
                    IBinder service = (IBinder) msg.obj;
                    try {
                        mBluetoothLock.writeLock().lock();
                        if (msg.arg1 == SERVICE_IBLUETOOTHGATT) {
                            mBluetoothGatt = IBluetoothGatt.Stub.asInterface(Binder.allowBlocking(service));
                            continueFromBleOnState();
                            break;
                        } 

    private void continueFromBleOnState() {
         ...
         mBluetooth.onLeServiceUp();
    }

BluetoothManagerService#enable講解最后這里拿到了service。同時(shí)也是這里的continueFromBleOnState脸秽,開(kāi)起了bluetooth apk里其他所有支持的profile的service儒老。
2、Adapterservice#startProfileServices
接著又是狀態(tài)機(jī)一頓切換豹储,切換流程和上面狀態(tài)機(jī)一樣贷盲,這里簡(jiǎn)略

void onLeServiceUp() {
        mAdapterStateMachine.sendMessage(AdapterState.USER_TURN_ON);
    }
 private class TurningOnState extends BaseAdapterState {
        @Override
        public void enter() {
            ...
            mAdapterService.startProfileServices();
        }

void startProfileServices() {
        Class[] supportedProfileServices = Config.getSupportedProfiles();
        ...
            setAllProfileServiceStates(supportedProfileServices, BluetoothAdapter.STATE_ON);
        }
    }
private void setAllProfileServiceStates(Class[] services, int state) {
        for (Class service : services) {
            if (GattService.class.getSimpleName().equals(service.getSimpleName())) {
                continue;
            }
            setProfileServiceState(service, state);
        }
    }

 private void setProfileServiceState(Class service, int state) {
        Intent intent = new Intent(this, service);
        intent.putExtra(EXTRA_ACTION, ACTION_SERVICE_STATE_CHANGED);
        intent.putExtra(BluetoothAdapter.EXTRA_STATE, state);
        startService(intent);
    }

Config.getSupportedProfiles拿到的是配置文件中列出來(lái)支持的所有協(xié)議。然后全部把profile的狀態(tài)置為STATE_ON
最后一個(gè)for循環(huán)遍歷startService開(kāi)起所有支持的服務(wù)

bluetooth apk小結(jié)
1剥扣、bluetooth apk是藍(lán)牙功能實(shí)現(xiàn)的地方巩剖。
2、bluetooth apk里的代碼主要靠adapterservice工作運(yùn)行钠怯。
3佳魔、adapterservice提供了底層so庫(kù)的入口。也提供了供framework使用的方法晦炊。
4鞠鲜、adapterservice藍(lán)牙操作相關(guān)主要靠AdapterState狀態(tài)機(jī)來(lái)切換

3.4、SettingsLib

1断国、SettingsLib和bluetoothAdapter類似以API運(yùn)用為主贤姆,這部分以表格方式
2、首先SettingsLib包含了很多功能稳衬,它的目的是封裝一些操作霞捡。專注服務(wù)于settings app。本文只對(duì)settingslib中bluetooth部分分析薄疚。本文開(kāi)頭部分簡(jiǎn)單介紹settingsLib的時(shí)候?qū)β窂较碌膒rofile進(jìn)行了表格統(tǒng)計(jì)碧信,并說(shuō)明了他們的功能。settingslib中的bletooth代碼除了這部分協(xié)議,剩下幾個(gè)LocalManager對(duì)藍(lán)牙的操作封裝處理街夭。這個(gè)Manager我們也先以表格的形式簡(jiǎn)單統(tǒng)計(jì)說(shuō)明砰碴。

名稱 簡(jiǎn)單介紹
LocalBluetoothAdapter 絕大部分都是對(duì)BluetoothAdapter間接調(diào)用
CachedBluetoothDeviceManager 管理已配對(duì)設(shè)備列表
BluetoothEventManager 接收藍(lán)牙相關(guān)廣播和藍(lán)牙的一些回調(diào),并根據(jù)UI操作執(zhí)行到對(duì)應(yīng)的事件
LocalBluetoothProfileManager 對(duì)外提供可用profile的訪問(wèn)
LocalBluetoothManager 統(tǒng)一管理CachedBluetoothDeviceManager板丽、LocalBluetoothProfileManager呈枉、BluetoothEventManager創(chuàng)建和獲取

有了前面三個(gè)部分的講解,settingslib的代碼看起來(lái)就很簡(jiǎn)單了埃碱。接下來(lái)分開(kāi)解析

3.4.1猖辫、LocalBluetoothAdapter裝飾者

LocalBluetoothAdapter用的是裝飾者模式,代理了BluetoothAdapter的一些方法乃正,并擴(kuò)展了極少功能住册。通篇LocalBluetoothAdapter的代碼除了代理外就把藍(lán)牙打開(kāi)狀態(tài)傳給了LocalBluetoothProfileManager

public boolean enable() {
        return mAdapter.enable();
    }

 synchronized void setBluetoothStateInt(int state) {
        mState = state;
        if (state == BluetoothAdapter.STATE_ON) {
            ...
            if (mProfileManager != null) {
                mProfileManager.setBluetoothStateOn();
            }
        }
    }

3.4.2、CachedBluetoothDeviceManager配對(duì)設(shè)備

CachedBluetoothDeviceManager管理已連接設(shè)備瓮具,里邊用兩個(gè)ArrayList一個(gè)Map來(lái)存儲(chǔ)荧飞。助聽(tīng)器設(shè)備單獨(dú)用了一個(gè)list存儲(chǔ)凡人。

對(duì)象 作用
List<CachedBluetoothDevice> mCachedDevices 已配對(duì)設(shè)備
List<CachedBluetoothDevice> mHearingAidDevicesNotAddedInCache 助聽(tīng)器列表供UI顯示
final Map<Long, CachedBluetoothDevice> mCachedDevicesMapForHearingAids 助聽(tīng)器是兩個(gè)設(shè)備時(shí),另一個(gè)設(shè)備存在這個(gè)list里

下面是CachedBluetoothDeviceManager提供的方法列表

方法 作用
getCachedDevicesCopy 拷貝已配對(duì)設(shè)備List
onDeviceDisappeared 設(shè)備消失
onDeviceNameUpdated 設(shè)備名稱更新
findDevice 存儲(chǔ)的兩個(gè)list中查找
addDevice 添加設(shè)備到對(duì)應(yīng)list/map
isPairAddedInCache 是否在配對(duì)列表中
getHearingAidPairDeviceSummary 已配對(duì)助聽(tīng)描述
addDeviceNotaddedInMap 添加到map
updateHearingAidsDevices 助聽(tīng)設(shè)備刷新?tīng)顟B(tài)后更新列表
getName 有名字返回名字叹阔,沒(méi)有名字返回mac地址
clearNonBondedDevices 從三個(gè)列表中移除沒(méi)有綁定過(guò)狀態(tài)的設(shè)備
onScanningStateChanged 開(kāi)始掃描更新排序狀態(tài)
onBtClassChanged 藍(lán)牙設(shè)備描述變化
onUuidChanged uuid變化
onBluetoothStateChanged 藍(lán)牙開(kāi)關(guān)挠轴,關(guān)閉需清空列表,打卡需刷新信息
onActiveDeviceChanged profile是否存活
onHiSyncIdChanged 助聽(tīng)設(shè)備類型變化
getHearingAidOtherDevice 獲得助聽(tīng)設(shè)備
hearingAidSwitchDisplayDevice 助聽(tīng)設(shè)備一對(duì)耳幢,選擇哪個(gè)顯示到UI列表
onProfileConnectionStateChanged 協(xié)議監(jiān)聽(tīng)刷新助聽(tīng)設(shè)備列表
onDeviceUnpaired 取消配對(duì)岸晦,更新列表
dispatchAudioModeChanged audio狀態(tài)變化

3.4.3、BluetoothEventManager處理Event變化

BluetoothEventManager接收藍(lán)牙相關(guān)廣播和藍(lán)牙的一些回調(diào)睛藻,并根據(jù)UI操作執(zhí)行到對(duì)應(yīng)的事件启上。
BluetoothEventManager設(shè)計(jì)思想也很簡(jiǎn)單,就是監(jiān)聽(tīng)所有需要關(guān)心的藍(lán)牙廣播店印。收到狀態(tài)后把傳給CallBack或者其他Manager
1冈在、構(gòu)造函數(shù)監(jiān)聽(tīng)廣播

 BluetoothEventManager(LocalBluetoothAdapter adapter,
            CachedBluetoothDeviceManager deviceManager, Context context) {
        ...
        // 藍(lán)牙開(kāi)關(guān)
        addHandler(BluetoothAdapter.ACTION_STATE_CHANGED, new AdapterStateChangedHandler());
        // 藍(lán)牙連接
        addHandler(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED,
                new ConnectionStateChangedHandler());

        // 藍(lán)牙發(fā)現(xiàn)廣播
        addHandler(BluetoothAdapter.ACTION_DISCOVERY_STARTED, new ScanningStateChangedHandler(true));
        addHandler(BluetoothAdapter.ACTION_DISCOVERY_FINISHED, new ScanningStateChangedHandler(false));
        addHandler(BluetoothDevice.ACTION_FOUND, new DeviceFoundHandler());
        addHandler(BluetoothDevice.ACTION_DISAPPEARED, new DeviceDisappearedHandler());
        addHandler(BluetoothDevice.ACTION_NAME_CHANGED, new NameChangedHandler());
        addHandler(BluetoothDevice.ACTION_ALIAS_CHANGED, new NameChangedHandler());

        //配對(duì)
        addHandler(BluetoothDevice.ACTION_BOND_STATE_CHANGED, new BondStateChangedHandler());

        // 遠(yuǎn)端設(shè)備描述信息
        addHandler(BluetoothDevice.ACTION_CLASS_CHANGED, new ClassChangedHandler());
        addHandler(BluetoothDevice.ACTION_UUID, new UuidChangedHandler());
        addHandler(BluetoothDevice.ACTION_BATTERY_LEVEL_CHANGED, new BatteryLevelChangedHandler());

        // 藍(lán)牙底座設(shè)備狀態(tài),比如車載電源充電狀態(tài)
        addHandler(Intent.ACTION_DOCK_EVENT, new DockEventHandler());

        //藍(lán)牙協(xié)議開(kāi)始活動(dòng)廣播
        addHandler(BluetoothA2dp.ACTION_ACTIVE_DEVICE_CHANGED,
                   new ActiveDeviceChangedHandler());
        addHandler(BluetoothHeadset.ACTION_ACTIVE_DEVICE_CHANGED,
                   new ActiveDeviceChangedHandler());
        addHandler(BluetoothHearingAid.ACTION_ACTIVE_DEVICE_CHANGED,
                   new ActiveDeviceChangedHandler());

        // 音頻策略按摘,聯(lián)系人
        addHandler(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED,
                new AudioModeChangedHandler());
        addHandler(TelephonyManager.ACTION_PHONE_STATE_CHANGED,
                new AudioModeChangedHandler());
       ...
    }

2包券、回調(diào)給監(jiān)聽(tīng)
廣播來(lái)了,就遍歷回調(diào)Callback炫贤,給manager設(shè)置狀態(tài)溅固。以StateChanged舉例:

private class AdapterStateChangedHandler implements Handler {
        public void onReceive(Context context, Intent intent,
                BluetoothDevice device) {
            int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE,
                                    BluetoothAdapter.ERROR);
            // Reregister Profile Broadcast Receiver as part of TURN OFF
            if (state == BluetoothAdapter.STATE_OFF)
            {
                context.unregisterReceiver(mProfileBroadcastReceiver);
                registerProfileIntentReceiver();
            }
            // update local profiles and get paired devices
            mLocalAdapter.setBluetoothStateInt(state);
            // send callback to update UI and possibly start scanning
            synchronized (mCallbacks) {
                for (BluetoothCallback callback : mCallbacks) {
                    callback.onBluetoothStateChanged(state);
                }
            }
            // Inform CachedDeviceManager that the adapter state has changed
            mDeviceManager.onBluetoothStateChanged(state);
        }
    }

**3、BluetoothCallback **
親切的BluetoothCallback 兰珍,我們監(jiān)聽(tīng)都是從這兒來(lái)監(jiān)聽(tīng)

public interface BluetoothCallback {
    void onBluetoothStateChanged(int bluetoothState);
    void onScanningStateChanged(boolean started);
    void onDeviceAdded(CachedBluetoothDevice cachedDevice);
    void onDeviceDeleted(CachedBluetoothDevice cachedDevice);
    void onDeviceBondStateChanged(CachedBluetoothDevice cachedDevice, int bondState);
    void onConnectionStateChanged(CachedBluetoothDevice cachedDevice, int state);
    void onActiveDeviceChanged(CachedBluetoothDevice activeDevice, int bluetoothProfile);
    void onAudioModeChanged();
    default void onProfileConnectionStateChanged(CachedBluetoothDevice cachedDevice,
            int state, int bluetoothProfile) {
    }
}

3.4.4侍郭、LocalBluetoothProfileManager

LocalBluetoothProfileManager是統(tǒng)一管理settings支持的profile的地方,提供profile的訪問(wèn)和狀態(tài)變化監(jiān)聽(tīng)俩垃。profile創(chuàng)建和綁定的流程在BluetoothManagerService部分已經(jīng)分析励幼。這些profile也是文章開(kāi)頭部分列出settinglib中的profile汰寓。用了Map<String, LocalBluetoothProfile>mProfileNameMap 來(lái)存儲(chǔ)口柳。

private A2dpProfile mA2dpProfile;
    private A2dpSinkProfile mA2dpSinkProfile;
    private HeadsetProfile mHeadsetProfile;
    private HfpClientProfile mHfpClientProfile;
    private MapProfile mMapProfile;
    private MapClientProfile mMapClientProfile;
    private HidProfile mHidProfile;
    private HidDeviceProfile mHidDeviceProfile;
    private OppProfile mOppProfile;
    private PanProfile mPanProfile;
    private PbapClientProfile mPbapClientProfile;
    private PbapServerProfile mPbapProfile;
    private final boolean mUsePbapPce;
    private final boolean mUseMapClient;
    private HearingAidProfile mHearingAidProfile;

創(chuàng)建的代碼都在打開(kāi)藍(lán)牙的時(shí)候調(diào)用setBluetoothStateOn

 void setBluetoothStateOn() {
        if (mHidProfile == null) {
        mHidProfile = new HidProfile(mContext, mLocalAdapter, mDeviceManager, this);
        addProfile(mHidProfile, HidProfile.NAME,
                BluetoothHidHost.ACTION_CONNECTION_STATE_CHANGED);
       }
       if (mPanProfile == null) {
        mPanProfile = new PanProfile(mContext, mLocalAdapter);
        addPanProfile(mPanProfile, PanProfile.NAME,
                BluetoothPan.ACTION_CONNECTION_STATE_CHANGED);
       }
       if (mHidDeviceProfile == null) {
       mHidDeviceProfile = new HidDeviceProfile(mContext, mLocalAdapter, mDeviceManager, this);
       addProfile(mHidDeviceProfile, HidDeviceProfile.NAME,
                BluetoothHidDevice.ACTION_CONNECTION_STATE_CHANGED);
       }
    ....
    //等等其他profile創(chuàng)建

3.4.5、LocalBluetoothManager

LocalBluetoothManager是這個(gè)manager里最簡(jiǎn)單的了就是創(chuàng)建著幾個(gè)manager有滑,方便對(duì)外獲取manager跃闹。

private LocalBluetoothManager(LocalBluetoothAdapter adapter, Context context) {
        mContext = context;
        mLocalAdapter = adapter;

        mCachedDeviceManager = new CachedBluetoothDeviceManager(context, this);
        mEventManager = new BluetoothEventManager(mLocalAdapter,
                mCachedDeviceManager, context);
        mProfileManager = new LocalBluetoothProfileManager(context,
                mLocalAdapter, mCachedDeviceManager, mEventManager);
        mEventManager.readPairedDevices();
    }

SettingsLib小結(jié)
1、SettingsLib主要供settings使用毛好,封裝一些操作望艺。
2、四個(gè)部分(代理Adapter肌访、管理配對(duì)設(shè)備找默、管理profile、監(jiān)聽(tīng)藍(lán)牙狀態(tài))

四吼驶、寫在最后

1惩激、通篇文章下來(lái)店煞,我們可以看到Android藍(lán)牙的架構(gòu)并不復(fù)雜。client提供對(duì)外接口风钻,service通過(guò)綁定Bluetooth中Adapterservice對(duì)接上具體實(shí)現(xiàn)顷蟀。最后settingslib封裝一些操作供settings使用更便捷。層次分明骡技。不像其他系統(tǒng)service和別的系統(tǒng)service有很多相互作用操作鸣个。
2、框架層的講解為的是幫助大家對(duì)Android藍(lán)牙整體的理解布朦。往細(xì)了講囤萤,service、Bluetooth是趴、settings里邊還有很多細(xì)節(jié)代碼可以扣阁将。每個(gè)profile還有很具體的用法用例。
3右遭、源碼真香

Read the fucking source code!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末做盅,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子窘哈,更是在濱河造成了極大的恐慌吹榴,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,682評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件滚婉,死亡現(xiàn)場(chǎng)離奇詭異图筹,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)让腹,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,277評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門远剩,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人骇窍,你說(shuō)我怎么就攤上這事瓜晤。” “怎么了腹纳?”我有些...
    開(kāi)封第一講書人閱讀 165,083評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵痢掠,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我嘲恍,道長(zhǎng)足画,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書人閱讀 58,763評(píng)論 1 295
  • 正文 為了忘掉前任佃牛,我火速辦了婚禮淹辞,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘俘侠。我一直安慰自己象缀,他們只是感情好彬向,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,785評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著攻冷,像睡著了一般娃胆。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上等曼,一...
    開(kāi)封第一講書人閱讀 51,624評(píng)論 1 305
  • 那天里烦,我揣著相機(jī)與錄音,去河邊找鬼禁谦。 笑死胁黑,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的州泊。 我是一名探鬼主播丧蘸,決...
    沈念sama閱讀 40,358評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼遥皂!你這毒婦竟也來(lái)了力喷?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書人閱讀 39,261評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤演训,失蹤者是張志新(化名)和其女友劉穎弟孟,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體样悟,經(jīng)...
    沈念sama閱讀 45,722評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡拂募,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了窟她。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片陈症。...
    茶點(diǎn)故事閱讀 40,030評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖震糖,靈堂內(nèi)的尸體忽然破棺而出录肯,到底是詐尸還是另有隱情,我是刑警寧澤试伙,帶...
    沈念sama閱讀 35,737評(píng)論 5 346
  • 正文 年R本政府宣布嘁信,位于F島的核電站于样,受9級(jí)特大地震影響疏叨,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜穿剖,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,360評(píng)論 3 330
  • 文/蒙蒙 一蚤蔓、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧糊余,春花似錦秀又、人聲如沸单寂。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 31,941評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)宣决。三九已至,卻和暖如春昏苏,著一層夾襖步出監(jiān)牢的瞬間尊沸,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 33,057評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工贤惯, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留洼专,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,237評(píng)論 3 371
  • 正文 我出身青樓孵构,卻偏偏與公主長(zhǎng)得像屁商,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子颈墅,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,976評(píng)論 2 355

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