bluetooth_gatt_discoverer_winrt.cc 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456
  1. // Copyright 2018 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "device/bluetooth/bluetooth_gatt_discoverer_winrt.h"
  5. #include <windows.foundation.collections.h>
  6. #include <utility>
  7. #include "base/bind.h"
  8. #include "base/containers/contains.h"
  9. #include "base/logging.h"
  10. #include "base/strings/stringprintf.h"
  11. #include "base/win/post_async_results.h"
  12. #include "components/device_event_log/device_event_log.h"
  13. #include "device/bluetooth/bluetooth_remote_gatt_service_winrt.h"
  14. #include "device/bluetooth/public/cpp/bluetooth_uuid.h"
  15. namespace device {
  16. namespace {
  17. using ABI::Windows::Devices::Bluetooth::IBluetoothLEDevice;
  18. using ABI::Windows::Devices::Bluetooth::IBluetoothLEDevice3;
  19. using ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::
  20. GattCharacteristic;
  21. using ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::
  22. GattCharacteristicsResult;
  23. using ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::
  24. GattCommunicationStatus;
  25. using ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::
  26. GattCommunicationStatus_AccessDenied;
  27. using ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::
  28. GattCommunicationStatus_Success;
  29. using ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::GattDescriptor;
  30. using ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::
  31. GattDescriptorsResult;
  32. using ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::
  33. GattDeviceService;
  34. using ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::
  35. GattDeviceServicesResult;
  36. using ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::GattOpenStatus;
  37. using ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::
  38. GattOpenStatus_AlreadyOpened;
  39. using ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::
  40. GattOpenStatus_Success;
  41. using ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::
  42. GattSharingMode;
  43. using ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::
  44. GattSharingMode_SharedReadAndWrite;
  45. using ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::
  46. IGattCharacteristic3;
  47. using ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::
  48. IGattCharacteristicsResult;
  49. using ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::
  50. IGattDescriptorsResult;
  51. using ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::
  52. IGattDeviceService;
  53. using ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::
  54. IGattDeviceService3;
  55. using ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::
  56. IGattDeviceServicesResult;
  57. using ABI::Windows::Foundation::IAsyncOperation;
  58. using ABI::Windows::Foundation::IReference;
  59. using ABI::Windows::Foundation::Collections::IVectorView;
  60. using Microsoft::WRL::ComPtr;
  61. std::string GattCommunicationStatusToString(GattCommunicationStatus status) {
  62. switch (status) {
  63. case GattCommunicationStatus_Success:
  64. return "Success";
  65. case ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::
  66. GattCommunicationStatus_Unreachable:
  67. return "Unreachable";
  68. case ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::
  69. GattCommunicationStatus_ProtocolError:
  70. return "ProtocolError";
  71. case GattCommunicationStatus_AccessDenied:
  72. return "AccessDenied";
  73. default:
  74. return base::StringPrintf("Unknown (%d)", status);
  75. }
  76. }
  77. std::string GattOpenStatusToString(GattOpenStatus status) {
  78. switch (status) {
  79. case ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::
  80. GattOpenStatus_Unspecified:
  81. return "Unspecified";
  82. case GattOpenStatus_Success:
  83. return "Success";
  84. case GattOpenStatus_AlreadyOpened:
  85. return "AlreadyOpened";
  86. case ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::
  87. GattOpenStatus_NotFound:
  88. return "NotFound";
  89. case ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::
  90. GattOpenStatus_SharingViolation:
  91. return "SharingViolation";
  92. case ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::
  93. GattOpenStatus_AccessDenied:
  94. return "AccessDenied";
  95. default:
  96. return base::StringPrintf("Unknown (%d)", status);
  97. }
  98. }
  99. template <typename IGattResult>
  100. bool CheckCommunicationStatus(IGattResult* gatt_result,
  101. bool allow_access_denied = false) {
  102. if (!gatt_result) {
  103. BLUETOOTH_LOG(DEBUG) << "Getting GATT Results failed.";
  104. return false;
  105. }
  106. GattCommunicationStatus status;
  107. HRESULT hr = gatt_result->get_Status(&status);
  108. if (FAILED(hr)) {
  109. BLUETOOTH_LOG(DEBUG) << "Getting GATT Communication Status failed: "
  110. << logging::SystemErrorCodeToString(hr);
  111. return false;
  112. }
  113. if (status != GattCommunicationStatus_Success) {
  114. if (status == GattCommunicationStatus_AccessDenied) {
  115. BLUETOOTH_LOG(DEBUG) << "GATT access denied error";
  116. } else {
  117. BLUETOOTH_LOG(DEBUG) << "Unexpected GattCommunicationStatus: "
  118. << GattCommunicationStatusToString(status);
  119. }
  120. BLUETOOTH_LOG(DEBUG)
  121. << "GATT Error Code: "
  122. << static_cast<int>(
  123. BluetoothRemoteGattServiceWinrt::GetGattErrorCode(gatt_result));
  124. }
  125. return status == GattCommunicationStatus_Success ||
  126. (allow_access_denied &&
  127. status == GattCommunicationStatus_AccessDenied);
  128. }
  129. template <typename T, typename I>
  130. bool GetAsVector(IVectorView<T*>* view, std::vector<ComPtr<I>>* vector) {
  131. unsigned size;
  132. HRESULT hr = view->get_Size(&size);
  133. if (FAILED(hr)) {
  134. BLUETOOTH_LOG(DEBUG) << "Getting Size failed: "
  135. << logging::SystemErrorCodeToString(hr);
  136. return false;
  137. }
  138. vector->reserve(size);
  139. for (unsigned i = 0; i < size; ++i) {
  140. ComPtr<I> entry;
  141. hr = view->GetAt(i, &entry);
  142. if (FAILED(hr)) {
  143. BLUETOOTH_LOG(DEBUG) << "GetAt(" << i << ") failed: "
  144. << logging::SystemErrorCodeToString(hr);
  145. return false;
  146. }
  147. vector->push_back(std::move(entry));
  148. }
  149. return true;
  150. }
  151. } // namespace
  152. BluetoothGattDiscovererWinrt::BluetoothGattDiscovererWinrt(
  153. ComPtr<IBluetoothLEDevice> ble_device,
  154. absl::optional<BluetoothUUID> service_uuid)
  155. : ble_device_(std::move(ble_device)),
  156. service_uuid_(std::move(service_uuid)) {}
  157. BluetoothGattDiscovererWinrt::~BluetoothGattDiscovererWinrt() = default;
  158. void BluetoothGattDiscovererWinrt::StartGattDiscovery(
  159. GattDiscoveryCallback callback) {
  160. callback_ = std::move(callback);
  161. ComPtr<IBluetoothLEDevice3> ble_device_3;
  162. HRESULT hr = ble_device_.As(&ble_device_3);
  163. if (FAILED(hr)) {
  164. BLUETOOTH_LOG(DEBUG) << "Obtaining IBluetoothLEDevice3 failed: "
  165. << logging::SystemErrorCodeToString(hr);
  166. std::move(callback_).Run(false);
  167. return;
  168. }
  169. ComPtr<IAsyncOperation<GattDeviceServicesResult*>> get_gatt_services_op;
  170. if (service_uuid_.has_value()) {
  171. hr = ble_device_3->GetGattServicesForUuidAsync(
  172. BluetoothUUID::GetCanonicalValueAsGUID(
  173. service_uuid_->canonical_value()),
  174. &get_gatt_services_op);
  175. } else {
  176. hr = ble_device_3->GetGattServicesAsync(&get_gatt_services_op);
  177. }
  178. if (FAILED(hr)) {
  179. BLUETOOTH_LOG(DEBUG) << "BluetoothLEDevice::GetGattServicesAsync failed: "
  180. << logging::SystemErrorCodeToString(hr);
  181. std::move(callback_).Run(false);
  182. return;
  183. }
  184. hr = base::win::PostAsyncResults(
  185. std::move(get_gatt_services_op),
  186. base::BindOnce(&BluetoothGattDiscovererWinrt::OnGetGattServices,
  187. weak_ptr_factory_.GetWeakPtr()));
  188. if (FAILED(hr)) {
  189. BLUETOOTH_LOG(DEBUG) << "PostAsyncResults failed: "
  190. << logging::SystemErrorCodeToString(hr);
  191. std::move(callback_).Run(false);
  192. }
  193. }
  194. const BluetoothGattDiscovererWinrt::GattServiceList&
  195. BluetoothGattDiscovererWinrt::GetGattServices() const {
  196. return gatt_services_;
  197. }
  198. const BluetoothGattDiscovererWinrt::GattCharacteristicList*
  199. BluetoothGattDiscovererWinrt::GetCharacteristics(
  200. uint16_t service_attribute_handle) const {
  201. auto iter = service_to_characteristics_map_.find(service_attribute_handle);
  202. return iter != service_to_characteristics_map_.end() ? &iter->second
  203. : nullptr;
  204. }
  205. const BluetoothGattDiscovererWinrt::GattDescriptorList*
  206. BluetoothGattDiscovererWinrt::GetDescriptors(
  207. uint16_t characteristic_attribute_handle) const {
  208. auto iter =
  209. characteristic_to_descriptors_map_.find(characteristic_attribute_handle);
  210. return iter != characteristic_to_descriptors_map_.end() ? &iter->second
  211. : nullptr;
  212. }
  213. void BluetoothGattDiscovererWinrt::OnGetGattServices(
  214. ComPtr<IGattDeviceServicesResult> services_result) {
  215. if (!CheckCommunicationStatus(services_result.Get())) {
  216. BLUETOOTH_LOG(DEBUG) << "Failed to get GATT services.";
  217. std::move(callback_).Run(false);
  218. return;
  219. }
  220. ComPtr<IVectorView<GattDeviceService*>> services;
  221. HRESULT hr = services_result->get_Services(&services);
  222. if (FAILED(hr)) {
  223. BLUETOOTH_LOG(DEBUG) << "Getting GATT Services failed: "
  224. << logging::SystemErrorCodeToString(hr);
  225. std::move(callback_).Run(false);
  226. return;
  227. }
  228. if (!GetAsVector(services.Get(), &gatt_services_)) {
  229. std::move(callback_).Run(false);
  230. return;
  231. }
  232. num_services_ = gatt_services_.size();
  233. for (const auto& gatt_service : gatt_services_) {
  234. uint16_t service_attribute_handle;
  235. hr = gatt_service->get_AttributeHandle(&service_attribute_handle);
  236. if (FAILED(hr)) {
  237. BLUETOOTH_LOG(DEBUG) << "Getting AttributeHandle failed: "
  238. << logging::SystemErrorCodeToString(hr);
  239. std::move(callback_).Run(false);
  240. return;
  241. }
  242. ComPtr<IGattDeviceService3> gatt_service_3;
  243. hr = gatt_service.As(&gatt_service_3);
  244. if (FAILED(hr)) {
  245. BLUETOOTH_LOG(DEBUG) << "Obtaining IGattDeviceService3 failed: "
  246. << logging::SystemErrorCodeToString(hr);
  247. std::move(callback_).Run(false);
  248. return;
  249. }
  250. ComPtr<IAsyncOperation<GattOpenStatus>> open_op;
  251. hr =
  252. gatt_service_3->OpenAsync(GattSharingMode_SharedReadAndWrite, &open_op);
  253. if (FAILED(hr)) {
  254. BLUETOOTH_LOG(DEBUG) << "GattDeviceService::OpenAsync() failed: "
  255. << logging::SystemErrorCodeToString(hr);
  256. std::move(callback_).Run(false);
  257. }
  258. hr = base::win::PostAsyncResults(
  259. std::move(open_op),
  260. base::BindOnce(&BluetoothGattDiscovererWinrt::OnServiceOpen,
  261. weak_ptr_factory_.GetWeakPtr(),
  262. std::move(gatt_service_3), service_attribute_handle));
  263. }
  264. RunCallbackIfDone();
  265. }
  266. void BluetoothGattDiscovererWinrt::OnServiceOpen(
  267. ComPtr<IGattDeviceService3> gatt_service_3,
  268. uint16_t service_attribute_handle,
  269. GattOpenStatus status) {
  270. if (status != GattOpenStatus_Success &&
  271. status != GattOpenStatus_AlreadyOpened) {
  272. BLUETOOTH_LOG(DEBUG) << "Ignoring failure to open service "
  273. << service_attribute_handle << ": "
  274. << GattOpenStatusToString(status);
  275. // Enumerate no characteristics on services the browser is unable to access.
  276. service_to_characteristics_map_.insert({service_attribute_handle, {}});
  277. RunCallbackIfDone();
  278. return;
  279. }
  280. ComPtr<IAsyncOperation<GattCharacteristicsResult*>> get_characteristics_op;
  281. HRESULT hr = gatt_service_3->GetCharacteristicsAsync(&get_characteristics_op);
  282. if (FAILED(hr)) {
  283. BLUETOOTH_LOG(DEBUG)
  284. << "GattDeviceService::GetCharacteristicsAsync() failed: "
  285. << logging::SystemErrorCodeToString(hr);
  286. std::move(callback_).Run(false);
  287. return;
  288. }
  289. hr = base::win::PostAsyncResults(
  290. std::move(get_characteristics_op),
  291. base::BindOnce(&BluetoothGattDiscovererWinrt::OnGetCharacteristics,
  292. weak_ptr_factory_.GetWeakPtr(), service_attribute_handle));
  293. if (FAILED(hr)) {
  294. BLUETOOTH_LOG(DEBUG) << "PostAsyncResults failed: "
  295. << logging::SystemErrorCodeToString(hr);
  296. std::move(callback_).Run(false);
  297. }
  298. }
  299. void BluetoothGattDiscovererWinrt::OnGetCharacteristics(
  300. uint16_t service_attribute_handle,
  301. ComPtr<IGattCharacteristicsResult> characteristics_result) {
  302. // A few GATT services like HID over GATT (short UUID 0x1812) are protected
  303. // by the OS, leading to an access denied error.
  304. if (!CheckCommunicationStatus(characteristics_result.Get(),
  305. /*allow_access_denied=*/true)) {
  306. BLUETOOTH_LOG(DEBUG) << "Failed to get characteristics for service "
  307. << service_attribute_handle << ".";
  308. std::move(callback_).Run(false);
  309. return;
  310. }
  311. ComPtr<IVectorView<GattCharacteristic*>> characteristics;
  312. HRESULT hr = characteristics_result->get_Characteristics(&characteristics);
  313. if (FAILED(hr)) {
  314. BLUETOOTH_LOG(DEBUG) << "Getting Characteristics failed: "
  315. << logging::SystemErrorCodeToString(hr);
  316. std::move(callback_).Run(false);
  317. return;
  318. }
  319. DCHECK(!base::Contains(service_to_characteristics_map_,
  320. service_attribute_handle));
  321. auto& characteristics_list =
  322. service_to_characteristics_map_[service_attribute_handle];
  323. if (!GetAsVector(characteristics.Get(), &characteristics_list)) {
  324. std::move(callback_).Run(false);
  325. return;
  326. }
  327. num_characteristics_ += characteristics_list.size();
  328. for (const auto& gatt_characteristic : characteristics_list) {
  329. uint16_t characteristic_attribute_handle;
  330. hr = gatt_characteristic->get_AttributeHandle(
  331. &characteristic_attribute_handle);
  332. if (FAILED(hr)) {
  333. BLUETOOTH_LOG(DEBUG) << "Getting AttributeHandle failed: "
  334. << logging::SystemErrorCodeToString(hr);
  335. std::move(callback_).Run(false);
  336. return;
  337. }
  338. ComPtr<IGattCharacteristic3> gatt_characteristic_3;
  339. hr = gatt_characteristic.As(&gatt_characteristic_3);
  340. if (FAILED(hr)) {
  341. BLUETOOTH_LOG(DEBUG) << "Obtaining IGattCharacteristic3 failed: "
  342. << logging::SystemErrorCodeToString(hr);
  343. std::move(callback_).Run(false);
  344. return;
  345. }
  346. ComPtr<IAsyncOperation<GattDescriptorsResult*>> get_descriptors_op;
  347. hr = gatt_characteristic_3->GetDescriptorsAsync(&get_descriptors_op);
  348. if (FAILED(hr)) {
  349. BLUETOOTH_LOG(DEBUG)
  350. << "GattCharacteristic::GetDescriptorsAsync() failed: "
  351. << logging::SystemErrorCodeToString(hr);
  352. std::move(callback_).Run(false);
  353. return;
  354. }
  355. hr = base::win::PostAsyncResults(
  356. std::move(get_descriptors_op),
  357. base::BindOnce(&BluetoothGattDiscovererWinrt::OnGetDescriptors,
  358. weak_ptr_factory_.GetWeakPtr(),
  359. characteristic_attribute_handle));
  360. if (FAILED(hr)) {
  361. BLUETOOTH_LOG(DEBUG) << "PostAsyncResults failed: "
  362. << logging::SystemErrorCodeToString(hr);
  363. std::move(callback_).Run(false);
  364. }
  365. }
  366. RunCallbackIfDone();
  367. }
  368. void BluetoothGattDiscovererWinrt::OnGetDescriptors(
  369. uint16_t characteristic_attribute_handle,
  370. ComPtr<IGattDescriptorsResult> descriptors_result) {
  371. if (!CheckCommunicationStatus(descriptors_result.Get())) {
  372. BLUETOOTH_LOG(DEBUG) << "Failed to get descriptors for characteristic "
  373. << characteristic_attribute_handle << ".";
  374. std::move(callback_).Run(false);
  375. return;
  376. }
  377. ComPtr<IVectorView<GattDescriptor*>> descriptors;
  378. HRESULT hr = descriptors_result->get_Descriptors(&descriptors);
  379. if (FAILED(hr)) {
  380. BLUETOOTH_LOG(DEBUG) << "Getting descriptors failed: "
  381. << logging::SystemErrorCodeToString(hr);
  382. std::move(callback_).Run(false);
  383. return;
  384. }
  385. DCHECK(!base::Contains(characteristic_to_descriptors_map_,
  386. characteristic_attribute_handle));
  387. if (!GetAsVector(descriptors.Get(), &characteristic_to_descriptors_map_
  388. [characteristic_attribute_handle])) {
  389. std::move(callback_).Run(false);
  390. return;
  391. }
  392. RunCallbackIfDone();
  393. }
  394. void BluetoothGattDiscovererWinrt::RunCallbackIfDone() {
  395. DCHECK(callback_);
  396. if (service_to_characteristics_map_.size() == num_services_ &&
  397. characteristic_to_descriptors_map_.size() == num_characteristics_) {
  398. std::move(callback_).Run(true);
  399. }
  400. }
  401. } // namespace device