全面的了解蓝牙协议栈架构:https://www.cnblogs.com/blogs-of-lxl/p/7010061.html

蓝牙技术电子书:https://www.crifan.com/files/doc/docbook/bluetooth_intro/release/html/bluetooth_intro.html

蓝牙4.0 BLE 广播包解析:https://blog.csdn.net/qq576494799/article/details/52102642




HCI:https://blog.csdn.net/u010657219/article/details/42192481


HAL:https://blog.csdn.net/luoshengyang/article/details/6567257


https://blog.csdn.net/myarrow/article/details/7175204






Android 作为设备端

开源库:http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2018/0403/9551.html

demo :https://blog.csdn.net/z302766296/article/details/77816960


https://www.jianshu.com/p/c4f84af432a1



1.广播包:https://www.cnblogs.com/CharlesGrant/p/7155211.html









最近在做一个蓝牙开关的功能,发现一个很奇怪的现象:

1.打开蓝牙,蓝牙图标亮了,但是蓝牙不能被外界搜索到。只有从设置-蓝牙进入蓝牙扫描界面,此时蓝牙才能被外界搜索到。所以准备一探源码,看能否找到解决办法。




蓝牙enable源码分析

https://blog.csdn.net/ccc905341846/article/details/79009200

https://blog.csdn.net/zrf1335348191/article/details/53215281

https://www.cnblogs.com/chenbin7/p/3334082.html (超级详细


蓝牙扫描


https://www.cnblogs.com/libs-liu/p/9166075.html (蓝牙扫描)






从设备扫描主设备的蓝牙,蓝牙的地址,竟然不是主设备主机信息里显示的蓝牙地址,只有从源码

分析这个地址了:

1.首先这个地址是BluetoothDevice这个类里的mAddress变量,这个变量是从BluetoothDevice的构造方法传入的,而BluetoothDevice的构造方法在BluetoothAdapter类里被调用


继续搜索getRomoteService方法

1)在主设备BluetoothGattServer里会被调用到

在其mBluetoothGattServerCallback里会多处用到,用来创建一个BluetoothDevice对象,这个监听是监听从设备的。

注意:!!!!这些方法里的address是从设备的地址,并不是我们想要的主设备的地址!!!



所以还是得从从设备的代码出发寻找mac是从哪里获取的。

从设备里调用:



---------------------------------------------------------------------------------------------------------------

---------------------------------------------------------------------------------------------------------------

在网站源码搜索registerScanner:


registScanner方法

通过ScanManager的方法调用底层的ScanNative类注册扫描器的方法:


最终找到JNI源码调用的地方:/packages/apps/Bluetooth/jni/com_android_bluetooth_gatt.cpp

注意这里的CallVoidMethod 方法,调用的是java的方法:https://blog.csdn.net/lyh2299259684/article/details/79438802


onScanResult方法 (没有找到这个方法在哪里被调用了???)


其实吧,上面说了这么多,还是说从设备如何获取mac的,并没有说明主设备的mac到底是什么,怎么暴露给从设备的呢?

后来才发现,客户扫描的这个mac,实际上是设备在开启ble服务的时候通过广播发出去的。设备自己定义的mac。然后前面这个推断是错误的,这个mac地址还是android系统自己生成的。


https://blog.csdn.net/shuijianbaozi/article/details/75219530 (关于广播的mac为什么与本地的蓝牙mac不一致的问题)



看看设备发广播的源码 (8.0源码)

这里的mBluetoothManager实际上是BluetoothManagerService.java这个类

通过aidl和binder机制获取IBluetoothGatt对象

这里的binder对应的对象,我们使用的是BLE,所以应该是GattService对象。

所以看看GattService的startAdvertisingSet方法,注意这些方法都会有两个:

binder的方法



binder再会去调用GattService的方法

GattService再去调用AdvertiseManager的方法

注意上面,将advertiseData对象解析成了byte[]数据,也就是组织广播包的数据。看看这个方法是如何解析的:

packagecom.android.bluetooth.gatt;importandroid.bluetooth.BluetoothUuid;importandroid.bluetooth.le.AdvertiseData;importandroid.os.ParcelUuid;importandroid.util.Log;importcom.android.bluetooth.Utils;importjava.io.ByteArrayOutputStream;classAdvertiseHelper{privatestaticfinalStringTAG="AdvertiseHelper";privatestaticfinalintDEVICE_NAME_MAX=;privatestaticfinalintCOMPLETE_LIST__BIT_SERVICE_UUIDS=0X;privatestaticfinalintCOMPLETE_LIST__BIT_SERVICE_UUIDS=0X;privatestaticfinalintCOMPLETE_LIST__BIT_SERVICE_UUIDS=0X;privatestaticfinalintSHORTENED_LOCAL_NAME=0X;privatestaticfinalintCOMPLETE_LOCAL_NAME=0X;privatestaticfinalintTX_POWER_LEVEL=0x0A;privatestaticfinalintSERVICE_DATA__BIT_UUID=0X;privatestaticfinalintSERVICE_DATA__BIT_UUID=0X;privatestaticfinalintSERVICE_DATA__BIT_UUID=0X;privatestaticfinalintMANUFACTURER_SPECIFIC_DATA=0XFF;publicstaticbyte[]advertiseDataToBytes(AdvertiseDatadata,Stringname){if(data==null)returnnewbyte[0];//Flagsareaddedbylowerlayersofthestack,onlyifneeded;//noneedtoaddthemhere.ByteArrayOutputStreamret=newByteArrayOutputStream();if(data.getIncludeDeviceName()){try{byte[]nameBytes=name.getBytes("UTF-8");intnameLength=nameBytes.length;bytetype;//TODO(jpawlowski)putabetterlimitondevicename!if(nameLength>DEVICE_NAME_MAX){nameLength=DEVICE_NAME_MAX;type=SHORTENED_LOCAL_NAME;}else{type=COMPLETE_LOCAL_NAME;}ret.write(nameLength+1);ret.write(type);ret.write(nameBytes,0,nameLength);}catch(java.io.UnsupportedEncodingExceptione){Log.e(TAG,"Can'tincludename-encodingerror!",e);}}for(inti=0;i<data.getManufacturerSpecificData().size();i++){intmanufacturerId=data.getManufacturerSpecificData().keyAt(i);byte[]manufacturerData=data.getManufacturerSpecificData().get(manufacturerId);intdataLen=2+(manufacturerData==null?0:manufacturerData.length);byte[]concated=newbyte[dataLen];//Firsttwobytesaremanufactureridinlittle-endian.concated[0]=(byte)(manufacturerId&0xFF);concated[1]=(byte)((manufacturerId>>8)&0xFF);if(manufacturerData!=null){System.arraycopy(manufacturerData,0,concated,2,manufacturerData.length);}ret.write(concated.length+1);ret.write(MANUFACTURER_SPECIFIC_DATA);ret.write(concated,0,concated.length);}if(data.getIncludeTxPowerLevel()){ret.write(2/*Length*/);ret.write(TX_POWER_LEVEL);ret.write(0);//lowerlayerswillfillthisvalue.}if(data.getServiceUuids()!=null){ByteArrayOutputStreamserviceUuids=newByteArrayOutputStream();ByteArrayOutputStreamserviceUuids=newByteArrayOutputStream();ByteArrayOutputStreamserviceUuids=newByteArrayOutputStream();for(ParcelUuidparcelUuid:data.getServiceUuids()){byte[]uuid=BluetoothUuid.uuidToBytes(parcelUuid);if(uuid.length==BluetoothUuid.UUID_BYTES__BIT){serviceUuids.write(uuid,0,uuid.length);}elseif(uuid.length==BluetoothUuid.UUID_BYTES__BIT){serviceUuids.write(uuid,0,uuid.length);}else/*if(uuid.length==BluetoothUuid.UUID_BYTES__BIT)*/{serviceUuids.write(uuid,0,uuid.length);}}if(serviceUuids.size()!=0){ret.write(serviceUuids.size()+1);ret.write(COMPLETE_LIST__BIT_SERVICE_UUIDS);ret.write(serviceUuids.toByteArray(),0,serviceUuids.size());}if(serviceUuids.size()!=0){ret.write(serviceUuids.size()+1);ret.write(COMPLETE_LIST__BIT_SERVICE_UUIDS);ret.write(serviceUuids.toByteArray(),0,serviceUuids.size());}if(serviceUuids.size()!=0){ret.write(serviceUuids.size()+1);ret.write(COMPLETE_LIST__BIT_SERVICE_UUIDS);ret.write(serviceUuids.toByteArray(),0,serviceUuids.size());}}if(!data.getServiceData().isEmpty()){for(ParcelUuidparcelUuid:data.getServiceData().keySet()){byte[]serviceData=data.getServiceData().get(parcelUuid);byte[]uuid=BluetoothUuid.uuidToBytes(parcelUuid);intuuidLen=uuid.length;intdataLen=uuidLen+(serviceData==null?0:serviceData.length);byte[]concated=newbyte[dataLen];System.arraycopy(uuid,0,concated,0,uuidLen);if(serviceData!=null){System.arraycopy(serviceData,0,concated,uuidLen,serviceData.length);}if(uuid.length==BluetoothUuid.UUID_BYTES__BIT){ret.write(concated.length+1);ret.write(SERVICE_DATA__BIT_UUID);ret.write(concated,0,concated.length);}elseif(uuid.length==BluetoothUuid.UUID_BYTES__BIT){ret.write(concated.length+1);ret.write(SERVICE_DATA__BIT_UUID);ret.write(concated,0,concated.length);}else/*if(uuid.length==BluetoothUuid.UUID_BYTES__BIT)*/{ret.write(concated.length+1);ret.write(SERVICE_DATA__BIT_UUID);ret.write(concated,0,concated.length);}}}returnret.toByteArray();}}

Android 6.0 发起广播的源码解析:https://blog.csdn.net/lansefeiyang08/article/details/46545215


https://blog.csdn.net/lansefeiyang08/article/details/46505921

我对上面的博客源码作一下补充:

1)结构体btgatt_interface_t的位置

2)btgatt_client_interface_t所在的位置 /hardware/libhardware/include/hardware/bt_gatt_client.h

3)const btgatt_client_interface_t btgattClientInterface 映射所在的目录:/system/bt/btif/src/btif_gatt_client.c

4)BTA_GATTC_AppRegister方法所在目录:/system/bt/bta/gatt/bta_gattc_api.c

注意C这一层的跳转顺序:bt_gatt_client.h》btif_gatt_client.c》bta_gattc_api.c


继续找mac(Android 6.0源码,因为当前我们的系统就是6.0):

在上面源码的阅读过程中,我发现有这样的一个函数:

里面有一个address,我猜想这应该就是我一直苦苦寻求的mac。那么这个mac会回调到上层的某个回调里吗?事实证明前面的这个想法也是错误的,这里的地址还是客户端自己的地址。


设备如何设置的mac:https://blog.csdn.net/shichaog/article/details/52100954

但是并没有找到vendor_open方法调用的地方。


蓝牙初始化

1)获取蓝牙地址


这次这个地址是随机的,有可能是我想要的mac。




enable






下面的这个博客,看完一张图就能找到verdor_open的地方

https://blog.csdn.net/shichaog/article/details/52728684


根据上面的博客分析源码:

蓝牙Enable过程追踪(Android 6.0源码,因为当前我们的系统就是6.0):

根据上面的博客分析源码:



module_start_up:开启了两个module


一个module是hci_layer.c,在它的start_up方法里调用了vendor->open方法。也就是前面我提到的博客里的这个方法。




但是在vendor.c里,发现这个local_bdaddr仍然是本机信息里的那个固定的mac地址。




BTU_StartUp方法




》》》》BTU相关的源码开始


SMP_Init()方法




L2CA_RegisterFixedChannel这个方法貌似有mac的踪影



btm_ble_init()方法

这个地方貌似也有mac的踪影(这不正是开启广播start adv那个方法吗?):

给address赋值,注意在赋值之后调用了btm_ble_start_adv方法


BTE_InitStack()方法


》》》》BTU相关的源码结束



2018.9.14日,继续探索mac:

https://e2echina.ti.com/question_answer/wireless_connectivity/bluetooth/f/103/t/136174

https://www.cnblogs.com/CharlesGrant/p/7155812.html

https://blog.csdn.net/android_jiangjun/article/details/77113883

以上的博客,对ble广播的mac种类都做了一些说明,但是没有从源码里指明这个mac是在哪里如何生成的。

看到有这样的一个博客:https://devzone.nordicsemi.com/f/nordic-q-a/16720/setting-resolvable-private-address

通过在xref网站上搜索rpa,找到了一些蛛丝马迹:


/system/bt/stack/btm/btm_ble_multi_adv.c


/system/bt/stack/btm/btm_ble_addr.c

看这个类的注释:

对ble地址的管理,哈哈,是不是有戏?


看了一下它的各个函数,基本与上面博客提到的几种地址匹配上了。由于我们的设备是广播一旦开启,mac地址就会随机的变化。所以我猜想这个类里被调用的方法应该是Resolvable private address:

》》》》》》》》》》看btm_gen_resolve_paddr_cmpl方法:

这个方法, 和btsnd_hcic_ble_rand方法是关联的,主要是判断btsnd_hcic_ble_rand方法有没有执行成功。所以主要看btsnd_hcic_ble_rand方法。



》》》》》》》》》》看btsnd_hcic_ble_rand方法

说实话,看到这儿,我只看到给变量p申请了个内存空间,pp与p建立的关联,但是是哪里赋值的呢?

看看这个方法:








到这里,看得我一愣一愣的。 所幸我搜索android fixed_queue.c,找到下面这样一篇博客,说明了蓝牙协议栈通讯的来龙去脉。

############################################################################

android bluedroid 协议栈里面的各个组件之间的消息处理机制

https://blog.csdn.net/yanli0084/article/details/51821064

############################################################################

只能向前追溯了:

通过搜索MSG_STACK_TO_HC_HCI_CMD找到对应的处理位置:

根据case猜想到应该是btsnoop.c处理这个事件

看btsnoop_write_packet方法

staticvoidbtsnoop_write_packet(packet_type_ttype,constuint8_t*packet,boolis_received){intlength_he=0;intlength;intflags;intdrops=0;switch(type){casekCommandPacket:length_he=packet[2]+4;flags=2;break;casekAclPacket:length_he=(packet[3]<<8)+packet[2]+5;flags=is_received;break;casekScoPacket:length_he=packet[2]+4;flags=is_received;break;casekEventPacket:length_he=packet[1]+3;flags=3;break;}uint64_ttimestamp=btsnoop_timestamp();uint32_ttime_hi=timestamp>>32;uint32_ttime_lo=timestamp&0xFFFFFFFF;length=htonl(length_he);flags=htonl(flags);drops=htonl(drops);time_hi=htonl(time_hi);time_lo=htonl(time_lo);btsnoop_write(&length,4);btsnoop_write(&length,4);btsnoop_write(&flags,4);btsnoop_write(&drops,4);btsnoop_write(&time_hi,4);btsnoop_write(&time_lo,4);btsnoop_write(&type,1);btsnoop_write(packet,length_he-1);}

追踪,

这不正是把数据发送给client_socket吗?难道客户端与设备端的蓝牙通讯,底层是走了socket通讯?

那么,设备端与客户端的socket到底是怎么一回事,这个send方法又做了哪些事情。客户端又是怎么解析这些数据的呢?种种疑问立马在我脑海里浮现。

继续追溯send的调用栈:


2018.09.17,继续找mac:

/system/bt/stack/btm/btm_ble.c

上面的这些看似很像的方法,没有被调用 。



继续锲而不舍的找mac

这个local_rpa可以打印看一下,是否是mac。

|

追溯这个方法:

》》相关资料:

在HCI层ACL Connection的建立https://blog.csdn.net/gjsisi/article/details/13021253


》》





|


这不是前面说到的btu与hci的通讯吗,通过任务队列。


2018.9.18日,搜索mac旋转找到一篇博客,最后有人提出一个解决办法 :

https://stackoverflow.com/questions/28602672/android-5-static-bluetooth-mac-address-for-ble-advertising

将这个常量的true改成false(此方法亲测可用,就是不知道有什么安全隐患。)


而这篇中文博客:https://blog.csdn.net/shuijianbaozi/article/details/75219530,只说了有地址旋转这回事儿,但是没有提出解决办法。还是google找老外靠谱呢。




百度的一些修改蓝牙mac的方法,但是不适用于我的6.0的设备。

http://bbs.gfan.com/android-4369727-1-1.html


https://jingyan.baidu.com/article/17bd8e5250b6be85ab2bb8bf.html (android hex editor修改不了文件)



全局搜索BLE_PRIVACY_SPT这个变量,找寻可能暴露mac的地方。


1)

这里就是对随机还是固定的mac作了区分的地方。



2)