1 /*
2 * Copyright 2021 HIMSA II K/S - www.himsa.com.
3 * Represented by EHIMA - www.ehima.com
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18 #include <base/functional/bind.h>
19 #include <base/functional/callback.h>
20 #include <base/strings/string_number_conversions.h>
21 #include <bluetooth/log.h>
22 #include <hardware/bt_gatt_types.h>
23 #include <hardware/bt_has.h>
24
25 #include <list>
26 #include <map>
27 #include <mutex>
28 #include <string>
29 #include <vector>
30
31 #include "bta_csis_api.h"
32 #include "bta_gatt_api.h"
33 #include "bta_gatt_queue.h"
34 #include "bta_has_api.h"
35 #include "bta_le_audio_uuids.h"
36 #include "btm_sec.h"
37 #include "gap_api.h"
38 #include "gatt_api.h"
39 #include "has_types.h"
40 #include "internal_include/bt_trace.h"
41 #include "os/log.h"
42 #include "osi/include/properties.h"
43 #include "stack/include/bt_types.h"
44
45 using base::Closure;
46 using bluetooth::Uuid;
47 using bluetooth::csis::CsisClient;
48 using bluetooth::has::ConnectionState;
49 using bluetooth::has::ErrorCode;
50 using bluetooth::has::kFeatureBitPresetSynchronizationSupported;
51 using bluetooth::has::kHasPresetIndexInvalid;
52 using bluetooth::has::PresetInfo;
53 using bluetooth::has::PresetInfoReason;
54 using bluetooth::le_audio::has::HasClient;
55 using bluetooth::le_audio::has::HasCtpGroupOpCoordinator;
56 using bluetooth::le_audio::has::HasCtpNtf;
57 using bluetooth::le_audio::has::HasCtpOp;
58 using bluetooth::le_audio::has::HasDevice;
59 using bluetooth::le_audio::has::HasGattOpContext;
60 using bluetooth::le_audio::has::HasJournalRecord;
61 using bluetooth::le_audio::has::HasPreset;
62 using bluetooth::le_audio::has::kControlPointMandatoryOpcodesBitmask;
63 using bluetooth::le_audio::has::kControlPointSynchronizedOpcodesBitmask;
64 using bluetooth::le_audio::has::kUuidActivePresetIndex;
65 using bluetooth::le_audio::has::kUuidHearingAccessService;
66 using bluetooth::le_audio::has::kUuidHearingAidFeatures;
67 using bluetooth::le_audio::has::kUuidHearingAidPresetControlPoint;
68 using bluetooth::le_audio::has::PresetCtpChangeId;
69 using bluetooth::le_audio::has::PresetCtpOpcode;
70 using namespace bluetooth;
71
72 void btif_storage_add_leaudio_has_device(const RawAddress& address,
73 std::vector<uint8_t> presets_bin,
74 uint8_t features,
75 uint8_t active_preset);
76 bool btif_storage_get_leaudio_has_presets(const RawAddress& address,
77 std::vector<uint8_t>& presets_bin,
78 uint8_t& active_preset);
79 void btif_storage_set_leaudio_has_presets(const RawAddress& address,
80 std::vector<uint8_t> presets_bin);
81 bool btif_storage_get_leaudio_has_features(const RawAddress& address,
82 uint8_t& features);
83 void btif_storage_set_leaudio_has_features(const RawAddress& address,
84 uint8_t features);
85 void btif_storage_set_leaudio_has_active_preset(const RawAddress& address,
86 uint8_t active_preset);
87 void btif_storage_remove_leaudio_has(const RawAddress& address);
88
89 bool gatt_profile_get_eatt_support(const RawAddress& remote_bda);
90
91 namespace {
92 class HasClientImpl;
93 HasClientImpl* instance;
94 std::mutex instance_mutex;
95
96 /**
97 * -----------------------------------------------------------------------------
98 * Hearing Access Service - Client role
99 * -----------------------------------------------------------------------------
100 * Overview:
101 *
102 * This is Hearing Access Service client class.
103 *
104 * Each connected peer device supporting Hearing Access Service (HAS) is being
105 * connected and has its characteristics discovered. All the characteristics
106 * and descriptors (incl. the optional ones) are being read or written during
107 * this initial connection stage. Encryption is also verified. If all of this
108 * succeeds the appropriate callbacks are being called to notify upper layer
109 * about the successful HAS device connection and its features and the list
110 * of available audio configuration presets.
111 *
112 * Each HA device is expected to have the HAS service instantiated. It must
113 * contain Hearing Aid Features characteristic and optionally Presets Control
114 * Point and Active Preset Index characteristics, allowing the user to read
115 * preset details, switch currently active preset and possibly rename some of
116 * them.
117 *
118 * Hearing Aid Features characteristic informs the client about the type of
119 * Hearign Aids device (Monaural, Binaural or Banded), which operations are
120 * supported via the Preset Control Point characteristic, about dynamically
121 * changing list of available presets, writable presets and the support for
122 * synchronised preset change operations on the Binaural Hearing Aid devices.
123 */
124 class HasClientImpl : public HasClient {
125 public:
HasClientImpl(bluetooth::has::HasClientCallbacks * callbacks,base::Closure initCb)126 HasClientImpl(bluetooth::has::HasClientCallbacks* callbacks,
127 base::Closure initCb)
128 : gatt_if_(0), callbacks_(callbacks) {
129 BTA_GATTC_AppRegister(
130 [](tBTA_GATTC_EVT event, tBTA_GATTC* p_data) {
131 if (instance && p_data) instance->GattcCallback(event, p_data);
132 },
133 base::Bind(
134 [](base::Closure initCb, uint8_t client_id, uint8_t status) {
135 if (status != GATT_SUCCESS) {
136 log::error(
137 "Can't start Hearing Aid Service client profile - no gatt "
138 "clients left!");
139 return;
140 }
141 instance->gatt_if_ = client_id;
142 initCb.Run();
143 },
144 initCb),
145 true);
146 }
147
148 ~HasClientImpl() override = default;
149
Connect(const RawAddress & address)150 void Connect(const RawAddress& address) override {
151 log::info("{}", address);
152
153 if (!BTM_IsLinkKeyKnown(address, BT_TRANSPORT_LE)) {
154 log::error("Connecting {} when not bonded", address);
155 callbacks_->OnConnectionState(ConnectionState::DISCONNECTED, address);
156 return;
157 }
158
159 std::vector<RawAddress> addresses = {address};
160 auto csis_api = CsisClient::Get();
161 if (csis_api != nullptr) {
162 // Connect entire CAS set of devices
163 auto group_id = csis_api->GetGroupId(
164 address, bluetooth::Uuid::From16Bit(UUID_COMMON_AUDIO_SERVICE));
165 addresses = csis_api->GetDeviceList(group_id);
166 }
167
168 if (addresses.empty()) {
169 log::warn("{} is not part of any set", address);
170 addresses = {address};
171 }
172
173 for (auto const& addr : addresses) {
174 auto device = std::find_if(devices_.begin(), devices_.end(),
175 HasDevice::MatchAddress(addr));
176 if (device == devices_.end()) {
177 devices_.emplace_back(addr, true);
178 BTA_GATTC_Open(gatt_if_, addr, BTM_BLE_DIRECT_CONNECTION, false);
179
180 } else {
181 device->is_connecting_actively = true;
182 if (!device->IsConnected())
183 BTA_GATTC_Open(gatt_if_, addr, BTM_BLE_DIRECT_CONNECTION, false);
184 }
185 }
186 }
187
AddFromStorage(const RawAddress & address,uint8_t features,uint16_t is_acceptlisted)188 void AddFromStorage(const RawAddress& address, uint8_t features,
189 uint16_t is_acceptlisted) {
190 log::debug("{}, features=0x{:x}, isAcceptlisted={}", address, features,
191 is_acceptlisted);
192
193 /* Notify upper layer about the device */
194 callbacks_->OnDeviceAvailable(address, features);
195 if (is_acceptlisted) {
196 auto device = std::find_if(devices_.begin(), devices_.end(),
197 HasDevice::MatchAddress(address));
198 if (device == devices_.end())
199 devices_.push_back(HasDevice(address, features));
200
201 /* Connect in background */
202 BTA_GATTC_Open(gatt_if_, address, BTM_BLE_BKG_CONNECT_ALLOW_LIST, false);
203 }
204 }
205
Disconnect(const RawAddress & address)206 void Disconnect(const RawAddress& address) override {
207 log::debug("{}", address);
208
209 std::vector<RawAddress> addresses = {address};
210 auto csis_api = CsisClient::Get();
211 if (csis_api != nullptr) {
212 // Disconnect entire CAS set of devices
213 auto group_id = csis_api->GetGroupId(
214 address, bluetooth::Uuid::From16Bit(UUID_COMMON_AUDIO_SERVICE));
215 addresses = csis_api->GetDeviceList(group_id);
216 }
217
218 if (addresses.empty()) {
219 log::warn("{} is not part of any set", address);
220 addresses = {address};
221 }
222
223 for (auto const& addr : addresses) {
224 auto device = std::find_if(devices_.begin(), devices_.end(),
225 HasDevice::MatchAddress(addr));
226 if (device == devices_.end()) {
227 log::warn("Device not connected to profile{}", addr);
228 return;
229 }
230
231 auto conn_id = device->conn_id;
232 auto is_connecting_actively = device->is_connecting_actively;
233 devices_.erase(device);
234
235 if (conn_id != GATT_INVALID_CONN_ID) {
236 BTA_GATTC_Close(conn_id);
237 callbacks_->OnConnectionState(ConnectionState::DISCONNECTED, addr);
238 } else {
239 /* Removes active connection. */
240 if (is_connecting_actively) {
241 BTA_GATTC_CancelOpen(gatt_if_, addr, true);
242 callbacks_->OnConnectionState(ConnectionState::DISCONNECTED, addr);
243 }
244 }
245
246 /* Removes all registrations for connection. */
247 BTA_GATTC_CancelOpen(0, addr, false);
248 }
249 }
250
UpdateJournalOpEntryStatus(HasDevice & device,HasGattOpContext context,tGATT_STATUS status)251 void UpdateJournalOpEntryStatus(HasDevice& device, HasGattOpContext context,
252 tGATT_STATUS status) {
253 /* Find journal entry by the context and update */
254 auto journal_entry = std::find_if(
255 device.has_journal_.begin(), device.has_journal_.end(),
256 [&context](auto const& record) {
257 if (record.is_operation) {
258 return HasGattOpContext(record.op_context_handle) == context;
259 }
260 return false;
261 });
262
263 if (journal_entry == device.has_journal_.end()) {
264 log::warn(
265 "Journaling error or journal length limit was set to low. Unable to "
266 "log the operation outcome.");
267 return;
268 }
269
270 if (journal_entry == device.has_journal_.end()) {
271 log::error("Unable to find operation context in the journal!");
272 return;
273 }
274
275 journal_entry->op_status = status;
276 }
277
ExtractPendingCtpOp(uint16_t op_id)278 std::optional<HasCtpOp> ExtractPendingCtpOp(uint16_t op_id) {
279 auto op_it =
280 std::find_if(pending_operations_.begin(), pending_operations_.end(),
281 [op_id](auto const& el) { return op_id == el.op_id; });
282
283 if (op_it != pending_operations_.end()) {
284 auto op = *op_it;
285 pending_operations_.erase(op_it);
286
287 return op;
288 }
289 return std::nullopt;
290 }
291
EnqueueCtpOp(HasCtpOp op)292 void EnqueueCtpOp(HasCtpOp op) { pending_operations_.push_back(op); }
293
OnHasActivePresetCycleStatus(uint16_t conn_id,tGATT_STATUS status,void * user_data)294 void OnHasActivePresetCycleStatus(uint16_t conn_id, tGATT_STATUS status,
295 void* user_data) {
296 log::debug("status: {}", status);
297
298 auto device = GetDevice(conn_id);
299 if (!device) {
300 log::warn("Device not connected to profile, conn_id={}", conn_id);
301 return;
302 }
303
304 /* Journal update */
305 log::assert_that(user_data != nullptr, "Has operation context is missing!");
306 auto context = HasGattOpContext(user_data);
307 UpdateJournalOpEntryStatus(*device, context, status);
308
309 auto op_opt = ExtractPendingCtpOp(context.ctp_op_id);
310 if (status == GATT_SUCCESS) return;
311
312 /* This could be one of the coordinated group preset change request */
313 pending_group_operation_timeouts_.erase(context.ctp_op_id);
314
315 /* Error handling */
316 if (!op_opt.has_value()) {
317 log::error("Unknown operation error");
318 return;
319 }
320 auto op = op_opt.value();
321 callbacks_->OnActivePresetSelectError(op.addr_or_group,
322 GattStatus2SvcErrorCode(status));
323
324 if (status == GATT_DATABASE_OUT_OF_SYNC) {
325 log::info("Database out of sync for {}", device->addr);
326 ClearDeviceInformationAndStartSearch(device);
327 }
328 }
329
OnHasPresetNameSetStatus(uint16_t conn_id,tGATT_STATUS status,void * user_data)330 void OnHasPresetNameSetStatus(uint16_t conn_id, tGATT_STATUS status,
331 void* user_data) {
332 auto device = GetDevice(conn_id);
333 if (!device) {
334 log::warn("Device not connected to profile, conn_id={}", conn_id);
335 return;
336 }
337
338 log::assert_that(user_data != nullptr, "Has operation context is missing!");
339 HasGattOpContext context(user_data);
340
341 /* Journal update */
342 UpdateJournalOpEntryStatus(*device, context, status);
343
344 auto op_opt = ExtractPendingCtpOp(context.ctp_op_id);
345 if (status == GATT_SUCCESS) return;
346
347 /* This could be one of the coordinated group preset change request */
348 pending_group_operation_timeouts_.erase(context.ctp_op_id);
349
350 /* Error handling */
351 if (!op_opt.has_value()) {
352 log::error("Unknown operation error");
353 return;
354 }
355 auto op = op_opt.value();
356 callbacks_->OnSetPresetNameError(device->addr, op.index,
357 GattStatus2SvcErrorCode(status));
358 if (status == GATT_DATABASE_OUT_OF_SYNC) {
359 log::info("Database out of sync for {}", device->addr);
360 ClearDeviceInformationAndStartSearch(device);
361 }
362 }
363
OnHasPresetNameGetStatus(uint16_t conn_id,tGATT_STATUS status,void * user_data)364 void OnHasPresetNameGetStatus(uint16_t conn_id, tGATT_STATUS status,
365 void* user_data) {
366 auto device = GetDevice(conn_id);
367 if (!device) {
368 log::warn("Device not connected to profile, conn_id={}", conn_id);
369 return;
370 }
371
372 log::assert_that(user_data != nullptr, "Has operation context is missing!");
373 HasGattOpContext context(user_data);
374
375 /* Journal update */
376 UpdateJournalOpEntryStatus(*device, context, status);
377
378 auto op_opt = ExtractPendingCtpOp(context.ctp_op_id);
379 if (status == GATT_SUCCESS) return;
380
381 /* Error handling */
382 if (!op_opt.has_value()) {
383 log::error("Unknown operation error");
384 return;
385 }
386 auto op = op_opt.value();
387 callbacks_->OnPresetInfoError(device->addr, op.index,
388 GattStatus2SvcErrorCode(status));
389
390 if (status == GATT_DATABASE_OUT_OF_SYNC) {
391 log::info("Database out of sync for {}", device->addr);
392 ClearDeviceInformationAndStartSearch(device);
393 } else {
394 log::error("Devices {}: Control point not usable. Disconnecting!",
395 device->addr);
396 BTA_GATTC_Close(device->conn_id);
397 }
398 }
399
OnHasPresetIndexOperation(uint16_t conn_id,tGATT_STATUS status,void * user_data)400 void OnHasPresetIndexOperation(uint16_t conn_id, tGATT_STATUS status,
401 void* user_data) {
402 log::debug("");
403
404 auto device = GetDevice(conn_id);
405 if (!device) {
406 log::warn("Device not connected to profile, conn_id={}", conn_id);
407 return;
408 }
409
410 log::assert_that(user_data != nullptr, "Has operation context is missing!");
411 HasGattOpContext context(user_data);
412
413 /* Journal update */
414 UpdateJournalOpEntryStatus(*device, context, status);
415
416 auto op_opt = ExtractPendingCtpOp(context.ctp_op_id);
417 if (status == GATT_SUCCESS) return;
418
419 /* This could be one of the coordinated group preset change request */
420 pending_group_operation_timeouts_.erase(context.ctp_op_id);
421
422 /* Error handling */
423 if (!op_opt.has_value()) {
424 log::error("Unknown operation error");
425 return;
426 }
427
428 auto op = op_opt.value();
429 if (op.opcode == PresetCtpOpcode::READ_PRESETS) {
430 callbacks_->OnPresetInfoError(device->addr, op.index,
431 GattStatus2SvcErrorCode(status));
432
433 } else {
434 callbacks_->OnActivePresetSelectError(op.addr_or_group,
435 GattStatus2SvcErrorCode(status));
436 }
437
438 if (status == GATT_DATABASE_OUT_OF_SYNC) {
439 log::info("Database out of sync for {}", device->addr);
440 ClearDeviceInformationAndStartSearch(device);
441 } else {
442 log::error("Devices {}: Control point not usable. Disconnecting!",
443 device->addr);
444 BTA_GATTC_Close(device->conn_id);
445 }
446 }
447
CpReadAllPresetsOperation(HasCtpOp operation)448 void CpReadAllPresetsOperation(HasCtpOp operation) {
449 log::debug("Operation: {}", operation);
450
451 if (std::holds_alternative<int>(operation.addr_or_group)) {
452 log::error("Read all presets on the entire group not supported.");
453 callbacks_->OnPresetInfoError(operation.addr_or_group, operation.index,
454 ErrorCode::OPERATION_NOT_POSSIBLE);
455 return;
456 }
457
458 auto device = std::find_if(
459 devices_.begin(), devices_.end(),
460 HasDevice::MatchAddress(std::get<RawAddress>(operation.addr_or_group)));
461 if (device == devices_.end()) {
462 log::warn("Device not connected to profile addr: {}",
463 std::get<RawAddress>(operation.addr_or_group));
464 callbacks_->OnPresetInfoError(device->addr, operation.index,
465 ErrorCode::OPERATION_NOT_POSSIBLE);
466 return;
467 }
468
469 if (!device->SupportsPresets()) {
470 callbacks_->OnPresetInfoError(device->addr, operation.index,
471 ErrorCode::OPERATION_NOT_SUPPORTED);
472 }
473
474 auto context = HasGattOpContext(operation);
475
476 /* Journal update */
477 device->has_journal_.Append(HasJournalRecord(operation, context));
478
479 /* Write to control point */
480 EnqueueCtpOp(operation);
481 BtaGattQueue::WriteCharacteristic(
482 device->conn_id, device->cp_handle, operation.ToCharacteristicValue(),
483 GATT_WRITE,
484 [](uint16_t conn_id, tGATT_STATUS status, uint16_t handle, uint16_t len,
485 const uint8_t* value, void* user_data) {
486 if (instance)
487 instance->OnHasPresetNameGetStatus(conn_id, status, user_data);
488 },
489 context);
490 }
491
CpPresetIndexOperationWriteReq(HasDevice & device,HasCtpOp & operation)492 ErrorCode CpPresetIndexOperationWriteReq(HasDevice& device,
493 HasCtpOp& operation) {
494 log::debug("Operation: {}", operation);
495
496 if (!device.IsConnected()) return ErrorCode::OPERATION_NOT_POSSIBLE;
497
498 if (!device.SupportsPresets()) return ErrorCode::OPERATION_NOT_SUPPORTED;
499
500 if (!device.SupportsOperation(operation.opcode))
501 return operation.IsGroupRequest()
502 ? ErrorCode::GROUP_OPERATION_NOT_SUPPORTED
503 : ErrorCode::OPERATION_NOT_SUPPORTED;
504
505 if (!device.IsValidPreset(operation.index))
506 return ErrorCode::INVALID_PRESET_INDEX;
507
508 auto context = HasGattOpContext(operation);
509
510 /* Journal update */
511 device.has_journal_.Append(HasJournalRecord(operation, context));
512
513 /* Write to control point */
514 EnqueueCtpOp(operation);
515 BtaGattQueue::WriteCharacteristic(
516 device.conn_id, device.cp_handle, operation.ToCharacteristicValue(),
517 GATT_WRITE,
518 [](uint16_t conn_id, tGATT_STATUS status, uint16_t handle, uint16_t len,
519 const uint8_t* value, void* user_data) {
520 if (instance)
521 instance->OnHasPresetIndexOperation(conn_id, status, user_data);
522 },
523 context);
524
525 return ErrorCode::NO_ERROR;
526 }
527
AreAllDevicesAvailable(const std::vector<RawAddress> & addresses)528 bool AreAllDevicesAvailable(const std::vector<RawAddress>& addresses) {
529 for (auto& addr : addresses) {
530 auto device = std::find_if(devices_.begin(), devices_.end(),
531 HasDevice::MatchAddress(addr));
532 if (device == devices_.end() || !device->IsConnected()) {
533 return false;
534 }
535 }
536 return true;
537 }
538
CpPresetOperationCaller(HasCtpOp operation,std::function<ErrorCode (HasDevice & device,HasCtpOp & operation)> write_cb)539 ErrorCode CpPresetOperationCaller(
540 HasCtpOp operation,
541 std::function<ErrorCode(HasDevice& device, HasCtpOp& operation)>
542 write_cb) {
543 log::debug("Operation: {}", operation);
544 auto status = ErrorCode::NO_ERROR;
545
546 if (operation.IsGroupRequest()) {
547 auto csis_api = CsisClient::Get();
548 if (csis_api == nullptr) {
549 /* No CSIS means no group operations */
550 status = ErrorCode::GROUP_OPERATION_NOT_SUPPORTED;
551
552 } else {
553 auto group_id = operation.GetGroupId();
554 auto addresses = csis_api->GetDeviceList(group_id);
555
556 /* Perform the operation only when all the devices are available */
557 if (!AreAllDevicesAvailable(addresses)) {
558 addresses.clear();
559 }
560
561 if (addresses.empty()) {
562 status = ErrorCode::OPERATION_NOT_POSSIBLE;
563
564 } else {
565 /* Make this a coordinated operation */
566 pending_group_operation_timeouts_.emplace(
567 operation.op_id, HasCtpGroupOpCoordinator(addresses, operation));
568
569 if (operation.IsSyncedOperation()) {
570 status = ErrorCode::GROUP_OPERATION_NOT_SUPPORTED;
571
572 /* Clear the error if we find device to forward the operation */
573 bool was_sent = false;
574 for (auto& addr : addresses) {
575 auto device = std::find_if(devices_.begin(), devices_.end(),
576 HasDevice::MatchAddress(addr));
577 if (device != devices_.end()) {
578 status = write_cb(*device, operation);
579 if (status == ErrorCode::NO_ERROR) {
580 was_sent = true;
581 break;
582 }
583 }
584 }
585 if (!was_sent) status = ErrorCode::OPERATION_NOT_POSSIBLE;
586
587 } else {
588 status = ErrorCode::GROUP_OPERATION_NOT_SUPPORTED;
589
590 for (auto& addr : addresses) {
591 auto device = std::find_if(devices_.begin(), devices_.end(),
592 HasDevice::MatchAddress(addr));
593 if (device != devices_.end()) {
594 status = write_cb(*device, operation);
595 if (status != ErrorCode::NO_ERROR) break;
596 }
597 }
598 }
599
600 /* Erase group op coordinator on error */
601 if (status != ErrorCode::NO_ERROR) {
602 pending_group_operation_timeouts_.erase(operation.op_id);
603 }
604 }
605 }
606
607 } else {
608 auto device = std::find_if(devices_.begin(), devices_.end(),
609 HasDevice::MatchAddress(std::get<RawAddress>(
610 operation.addr_or_group)));
611 status = ErrorCode::OPERATION_NOT_POSSIBLE;
612 if (device != devices_.end()) status = write_cb(*device, operation);
613 }
614
615 return status;
616 }
617
CpPresetIndexOperation(HasCtpOp operation)618 void CpPresetIndexOperation(HasCtpOp operation) {
619 log::info("Operation: {}", operation);
620
621 auto status = CpPresetOperationCaller(
622 operation, [](HasDevice& device, HasCtpOp operation) -> ErrorCode {
623 if (instance)
624 return instance->CpPresetIndexOperationWriteReq(device, operation);
625 return ErrorCode::OPERATION_NOT_POSSIBLE;
626 });
627
628 if (status != ErrorCode::NO_ERROR) {
629 switch (operation.opcode) {
630 case PresetCtpOpcode::READ_PRESETS:
631 log::assert_that(
632 std::holds_alternative<RawAddress>(operation.addr_or_group),
633 "Unsupported group operation!");
634
635 callbacks_->OnPresetInfoError(
636 std::get<RawAddress>(operation.addr_or_group), operation.index,
637 status);
638 break;
639 case PresetCtpOpcode::SET_ACTIVE_PRESET:
640 case PresetCtpOpcode::SET_ACTIVE_PRESET_SYNC:
641 callbacks_->OnActivePresetSelectError(operation.addr_or_group,
642 status);
643 break;
644 default:
645 break;
646 }
647 }
648 }
649
CpPresetsCycleOperationWriteReq(HasDevice & device,HasCtpOp & operation)650 ErrorCode CpPresetsCycleOperationWriteReq(HasDevice& device,
651 HasCtpOp& operation) {
652 log::debug("addr: {} operation: {}", device.addr, operation);
653
654 if (!device.IsConnected()) return ErrorCode::OPERATION_NOT_POSSIBLE;
655
656 if (!device.SupportsPresets()) return ErrorCode::OPERATION_NOT_SUPPORTED;
657
658 if (!device.SupportsOperation(operation.opcode))
659 return operation.IsGroupRequest()
660 ? ErrorCode::GROUP_OPERATION_NOT_SUPPORTED
661 : ErrorCode::OPERATION_NOT_SUPPORTED;
662
663 auto context = HasGattOpContext(operation);
664
665 /* Journal update */
666 device.has_journal_.Append(HasJournalRecord(operation, context));
667
668 /* Write to control point */
669 EnqueueCtpOp(operation);
670 BtaGattQueue::WriteCharacteristic(
671 device.conn_id, device.cp_handle, operation.ToCharacteristicValue(),
672 GATT_WRITE,
673 [](uint16_t conn_id, tGATT_STATUS status, uint16_t handle, uint16_t len,
674 const uint8_t* value, void* user_data) {
675 if (instance)
676 instance->OnHasActivePresetCycleStatus(conn_id, status, user_data);
677 },
678 context);
679 return ErrorCode::NO_ERROR;
680 }
681
CpPresetsCycleOperation(HasCtpOp operation)682 void CpPresetsCycleOperation(HasCtpOp operation) {
683 log::debug("Operation: {}", operation);
684
685 auto status = CpPresetOperationCaller(
686 operation, [](HasDevice& device, HasCtpOp operation) -> ErrorCode {
687 if (instance)
688 return instance->CpPresetsCycleOperationWriteReq(device, operation);
689 return ErrorCode::OPERATION_NOT_POSSIBLE;
690 });
691
692 if (status != ErrorCode::NO_ERROR)
693 callbacks_->OnActivePresetSelectError(operation.addr_or_group, status);
694 }
695
CpWritePresetNameOperationWriteReq(HasDevice & device,HasCtpOp operation)696 ErrorCode CpWritePresetNameOperationWriteReq(HasDevice& device,
697 HasCtpOp operation) {
698 log::debug("addr: {} operation: {}", device.addr, operation);
699
700 if (!device.IsConnected()) return ErrorCode::OPERATION_NOT_POSSIBLE;
701
702 if (!device.SupportsPresets()) return ErrorCode::OPERATION_NOT_SUPPORTED;
703
704 if (!device.IsValidPreset(operation.index, true))
705 return device.IsValidPreset(operation.index)
706 ? ErrorCode::SET_NAME_NOT_ALLOWED
707 : ErrorCode::INVALID_PRESET_INDEX;
708
709 if (!device.SupportsOperation(operation.opcode))
710 return ErrorCode::OPERATION_NOT_SUPPORTED;
711
712 if (operation.name.value_or("").length() >
713 bluetooth::le_audio::has::HasPreset::kPresetNameLengthLimit)
714 return ErrorCode::INVALID_PRESET_NAME_LENGTH;
715
716 auto context = HasGattOpContext(operation, operation.index);
717
718 /* Journal update */
719 device.has_journal_.Append(HasJournalRecord(operation, context));
720
721 /* Write to control point */
722 EnqueueCtpOp(operation);
723 BtaGattQueue::WriteCharacteristic(
724 device.conn_id, device.cp_handle, operation.ToCharacteristicValue(),
725 GATT_WRITE,
726 [](uint16_t conn_id, tGATT_STATUS status, uint16_t handle, uint16_t len,
727 const uint8_t* value, void* user_data) {
728 if (instance)
729 instance->OnHasPresetNameSetStatus(conn_id, status, user_data);
730 },
731 context);
732
733 return ErrorCode::NO_ERROR;
734 }
735
CpWritePresetNameOperation(HasCtpOp operation)736 void CpWritePresetNameOperation(HasCtpOp operation) {
737 log::debug("operation: {}", operation);
738
739 auto status = ErrorCode::NO_ERROR;
740
741 std::vector<RawAddress> addresses;
742 if (operation.IsGroupRequest()) {
743 auto csis_api = CsisClient::Get();
744 if (csis_api != nullptr) {
745 addresses = csis_api->GetDeviceList(operation.GetGroupId());
746
747 /* Make this a coordinated operation */
748 pending_group_operation_timeouts_.emplace(
749 operation.op_id, HasCtpGroupOpCoordinator(addresses, operation));
750 }
751
752 } else {
753 addresses = {operation.GetDeviceAddr()};
754 }
755
756 status = ErrorCode::OPERATION_NOT_POSSIBLE;
757
758 /* Perform the operation only when all the devices are available */
759 if (!AreAllDevicesAvailable(addresses)) {
760 addresses.clear();
761 }
762
763 for (auto& addr : addresses) {
764 auto device = std::find_if(devices_.begin(), devices_.end(),
765 HasDevice::MatchAddress(addr));
766 if (device != devices_.end()) {
767 status = CpWritePresetNameOperationWriteReq(*device, operation);
768 if (status != ErrorCode::NO_ERROR) {
769 log::error("Control point write error: {}", (int)status);
770 break;
771 }
772 }
773 }
774
775 if (status != ErrorCode::NO_ERROR) {
776 if (operation.IsGroupRequest())
777 pending_group_operation_timeouts_.erase(operation.op_id);
778
779 callbacks_->OnSetPresetNameError(operation.addr_or_group, operation.index,
780 status);
781 }
782 }
783
shouldRequestSyncedOp(std::variant<RawAddress,int> addr_or_group_id,PresetCtpOpcode opcode)784 bool shouldRequestSyncedOp(std::variant<RawAddress, int> addr_or_group_id,
785 PresetCtpOpcode opcode) {
786 /* Do not select locally synced ops when not performing group operations,
787 * You never know if the user will make another call for the other devices
788 * in this set even though the may support locally synced operations.
789 */
790 if (std::holds_alternative<RawAddress>(addr_or_group_id)) return false;
791
792 auto csis_api = CsisClient::Get();
793 if (csis_api == nullptr) return false;
794
795 auto addresses = csis_api->GetDeviceList(std::get<int>(addr_or_group_id));
796 if (addresses.empty()) return false;
797
798 for (auto& addr : addresses) {
799 auto device = std::find_if(devices_.begin(), devices_.end(),
800 HasDevice::MatchAddress(addr));
801 if (device != devices_.end()) {
802 if (device->SupportsOperation(opcode)) return true;
803 }
804 }
805
806 return false;
807 }
808
SelectActivePreset(std::variant<RawAddress,int> addr_or_group_id,uint8_t preset_index)809 void SelectActivePreset(std::variant<RawAddress, int> addr_or_group_id,
810 uint8_t preset_index) override {
811 log::debug("");
812
813 auto opcode = shouldRequestSyncedOp(addr_or_group_id,
814 PresetCtpOpcode::SET_ACTIVE_PRESET_SYNC)
815 ? PresetCtpOpcode::SET_ACTIVE_PRESET_SYNC
816 : PresetCtpOpcode::SET_ACTIVE_PRESET;
817
818 CpPresetIndexOperation(HasCtpOp(addr_or_group_id, opcode, preset_index));
819 }
820
NextActivePreset(std::variant<RawAddress,int> addr_or_group_id)821 void NextActivePreset(
822 std::variant<RawAddress, int> addr_or_group_id) override {
823 log::debug("");
824
825 auto opcode = shouldRequestSyncedOp(addr_or_group_id,
826 PresetCtpOpcode::SET_NEXT_PRESET_SYNC)
827 ? PresetCtpOpcode::SET_NEXT_PRESET_SYNC
828 : PresetCtpOpcode::SET_NEXT_PRESET;
829
830 CpPresetsCycleOperation(HasCtpOp(addr_or_group_id, opcode));
831 }
832
PreviousActivePreset(std::variant<RawAddress,int> addr_or_group_id)833 void PreviousActivePreset(
834 std::variant<RawAddress, int> addr_or_group_id) override {
835 log::debug("");
836
837 auto opcode = shouldRequestSyncedOp(addr_or_group_id,
838 PresetCtpOpcode::SET_PREV_PRESET_SYNC)
839 ? PresetCtpOpcode::SET_PREV_PRESET_SYNC
840 : PresetCtpOpcode::SET_PREV_PRESET;
841
842 CpPresetsCycleOperation(HasCtpOp(addr_or_group_id, opcode));
843 }
844
GetPresetInfo(const RawAddress & address,uint8_t preset_index)845 void GetPresetInfo(const RawAddress& address, uint8_t preset_index) override {
846 auto device = std::find_if(devices_.begin(), devices_.end(),
847 HasDevice::MatchAddress(address));
848 if (device == devices_.end()) {
849 log::warn("Device not connected to profile{}", address);
850 return;
851 }
852
853 log::debug("preset idx: {}", preset_index);
854
855 /* Due to mandatory control point notifications or indications, preset
856 * details are always up to date. However we have to be able to do the
857 * READ_PRESET_BY_INDEX, to pass the test specification requirements.
858 */
859 if (osi_property_get_bool("persist.bluetooth.has.always_use_preset_cache",
860 true)) {
861 auto* preset = device->GetPreset(preset_index);
862 if (preset == nullptr) {
863 log::error("Invalid preset request{}", address);
864 callbacks_->OnPresetInfoError(address, preset_index,
865 ErrorCode::INVALID_PRESET_INDEX);
866 return;
867 }
868
869 callbacks_->OnPresetInfo(address,
870 PresetInfoReason::PRESET_INFO_REQUEST_RESPONSE,
871 {{.preset_index = preset_index,
872 .writable = preset->IsWritable(),
873 .available = preset->IsAvailable(),
874 .preset_name = preset->GetName()}});
875 } else {
876 CpPresetIndexOperation(
877 HasCtpOp(address, PresetCtpOpcode::READ_PRESETS, preset_index));
878 }
879 }
880
SetPresetName(std::variant<RawAddress,int> addr_or_group_id,uint8_t preset_index,std::string name)881 void SetPresetName(std::variant<RawAddress, int> addr_or_group_id,
882 uint8_t preset_index, std::string name) override {
883 log::debug("preset_idx: {}, name: {}", preset_index, name);
884
885 CpWritePresetNameOperation(HasCtpOp(addr_or_group_id,
886 PresetCtpOpcode::WRITE_PRESET_NAME,
887 preset_index, 1 /* Don't care */, name));
888 }
889
CleanUp()890 void CleanUp() {
891 BTA_GATTC_AppDeregister(gatt_if_);
892 for (auto& device : devices_) {
893 if (device.conn_id != GATT_INVALID_CONN_ID)
894 BTA_GATTC_Close(device.conn_id);
895 DoDisconnectCleanUp(device);
896 }
897
898 devices_.clear();
899 pending_operations_.clear();
900 }
901
Dump(int fd) const902 void Dump(int fd) const {
903 std::stringstream stream;
904 stream << " APP ID: " << +gatt_if_ << " \n";
905 if (devices_.size()) {
906 stream << " {\"Known HAS devices\": [";
907 for (const auto& device : devices_) {
908 stream << "\n {";
909 device.Dump(stream);
910 stream << "\n },\n";
911 }
912 stream << " ]}\n\n";
913 } else {
914 stream << " \"No known HAS devices\"\n\n";
915 }
916 dprintf(fd, "%s", stream.str().c_str());
917 }
918
OnGroupOpCoordinatorTimeout(void * p)919 void OnGroupOpCoordinatorTimeout(void* p) {
920 log::error(
921 "Coordinated operation timeout: not all the devices notified their "
922 "state change on time.");
923
924 /* Clear pending group operations */
925 pending_group_operation_timeouts_.clear();
926 HasCtpGroupOpCoordinator::Cleanup();
927 }
928
929 private:
WriteAllNeededCcc(const HasDevice & device)930 void WriteAllNeededCcc(const HasDevice& device) {
931 if (device.conn_id == GATT_INVALID_CONN_ID) {
932 log::error("Device {} is not connected", device.addr);
933 return;
934 }
935
936 /* Write CCC values even remote should have it */
937 log::info("Subscribing for notification/indications");
938 if (device.SupportsFeaturesNotification()) {
939 SubscribeForNotifications(device.conn_id, device.addr,
940 device.features_handle,
941 device.features_ccc_handle);
942 }
943
944 if (device.SupportsPresets()) {
945 SubscribeForNotifications(device.conn_id, device.addr, device.cp_handle,
946 device.cp_ccc_handle, device.cp_ccc_val);
947 SubscribeForNotifications(device.conn_id, device.addr,
948 device.active_preset_handle,
949 device.active_preset_ccc_handle);
950 }
951
952 if (osi_property_get_bool("persist.bluetooth.has.always_use_preset_cache",
953 true) == false) {
954 CpReadAllPresetsOperation(
955 HasCtpOp(device.addr, PresetCtpOpcode::READ_PRESETS,
956 bluetooth::le_audio::has::kStartPresetIndex,
957 bluetooth::le_audio::has::kMaxNumOfPresets));
958 }
959 }
960
OnEncrypted(HasDevice & device)961 void OnEncrypted(HasDevice& device) {
962 log::debug("{}", device.addr);
963
964 if (device.isGattServiceValid()) {
965 device.is_connecting_actively = false;
966 NotifyHasDeviceValid(device);
967 callbacks_->OnPresetInfo(device.addr, PresetInfoReason::ALL_PRESET_INFO,
968 device.GetAllPresetInfo());
969 callbacks_->OnActivePresetSelected(device.addr,
970 device.currently_active_preset);
971 WriteAllNeededCcc(device);
972 } else {
973 BTA_GATTC_ServiceSearchRequest(device.conn_id, kUuidHearingAccessService);
974 }
975 }
976
NotifyHasDeviceValid(const HasDevice & device)977 void NotifyHasDeviceValid(const HasDevice& device) {
978 log::debug("addr:{}", device.addr);
979
980 std::vector<uint8_t> preset_indices;
981 preset_indices.reserve(device.has_presets.size());
982 for (auto const& preset : device.has_presets) {
983 preset_indices.push_back(preset.GetIndex());
984 }
985
986 /* Notify that we are ready to go */
987 callbacks_->OnConnectionState(ConnectionState::CONNECTED, device.addr);
988 }
989
MarkDeviceValidIfInInitialDiscovery(HasDevice & device)990 void MarkDeviceValidIfInInitialDiscovery(HasDevice& device) {
991 if (device.isGattServiceValid()) return;
992
993 --device.gatt_svc_validation_steps;
994
995 if (device.isGattServiceValid()) {
996 device.is_connecting_actively = false;
997
998 std::vector<uint8_t> presets_bin;
999 if (device.SerializePresets(presets_bin)) {
1000 btif_storage_add_leaudio_has_device(device.addr, presets_bin,
1001 device.GetFeatures(),
1002 device.currently_active_preset);
1003 }
1004 NotifyHasDeviceValid(device);
1005 }
1006 }
1007
OnGattWriteCcc(uint16_t conn_id,tGATT_STATUS status,uint16_t handle,void * user_data)1008 void OnGattWriteCcc(uint16_t conn_id, tGATT_STATUS status, uint16_t handle,
1009 void* user_data) {
1010 log::debug("handle=0x{:x}", handle);
1011
1012 auto device = GetDevice(conn_id);
1013 if (!device) {
1014 log::error("unknown conn_id=0x{:x}", conn_id);
1015 BtaGattQueue::Clean(conn_id);
1016 return;
1017 }
1018
1019 if (status == GATT_DATABASE_OUT_OF_SYNC) {
1020 log::info("Database out of sync for {}", device->addr);
1021 ClearDeviceInformationAndStartSearch(device);
1022 return;
1023 }
1024
1025 HasGattOpContext context(user_data);
1026 bool enabling_ntf = context.context_flags &
1027 HasGattOpContext::kContextFlagsEnableNotification;
1028
1029 if (handle == device->features_ccc_handle) {
1030 if (status == GATT_SUCCESS)
1031 device->features_notifications_enabled = enabling_ntf;
1032
1033 } else if ((handle == device->active_preset_ccc_handle) ||
1034 (handle == device->cp_ccc_handle)) {
1035 /* Both of these CCC are mandatory */
1036 if (enabling_ntf && (status != GATT_SUCCESS)) {
1037 log::error("Failed to register for notifications on handle=0x{:x}",
1038 handle);
1039 BTA_GATTC_Close(conn_id);
1040 return;
1041 }
1042 }
1043 }
1044
OnHasNotification(uint16_t conn_id,uint16_t handle,uint16_t len,const uint8_t * value)1045 void OnHasNotification(uint16_t conn_id, uint16_t handle, uint16_t len,
1046 const uint8_t* value) {
1047 auto device = GetDevice(conn_id);
1048 if (!device) {
1049 log::warn("Skipping unknown device, conn_id=0x{:x}", conn_id);
1050 return;
1051 }
1052
1053 if (handle == device->features_handle) {
1054 OnHasFeaturesValue(&(*device), GATT_SUCCESS, handle, len, value);
1055
1056 } else if (handle == device->cp_handle) {
1057 OnHasCtpValueNotification(&(*device), len, value);
1058
1059 } else if (handle == device->active_preset_handle) {
1060 OnHasActivePresetValue(&(*device), GATT_SUCCESS, handle, len, value);
1061 }
1062 }
1063
1064 /* Gets the device from variant, possibly searching by conn_id */
GetDevice(std::variant<uint16_t,HasDevice * > conn_id_device_variant)1065 HasDevice* GetDevice(
1066 std::variant<uint16_t, HasDevice*> conn_id_device_variant) {
1067 HasDevice* device = nullptr;
1068
1069 if (std::holds_alternative<HasDevice*>(conn_id_device_variant)) {
1070 device = std::get<HasDevice*>(conn_id_device_variant);
1071 } else {
1072 auto it = std::find_if(
1073 devices_.begin(), devices_.end(),
1074 HasDevice::MatchConnId(std::get<uint16_t>(conn_id_device_variant)));
1075 if (it != devices_.end()) device = &(*it);
1076 }
1077
1078 return device;
1079 }
1080
OnHasFeaturesValue(std::variant<uint16_t,HasDevice * > conn_id_device_variant,tGATT_STATUS status,uint16_t handle,uint16_t len,const uint8_t * value,void * user_data=nullptr)1081 void OnHasFeaturesValue(
1082 std::variant<uint16_t, HasDevice*> conn_id_device_variant,
1083 tGATT_STATUS status, uint16_t handle, uint16_t len, const uint8_t* value,
1084 void* user_data = nullptr) {
1085 log::debug("");
1086
1087 auto device = GetDevice(conn_id_device_variant);
1088 if (!device) {
1089 log::error("Unknown device!");
1090 return;
1091 }
1092
1093 if (status != GATT_SUCCESS) {
1094 if (status == GATT_DATABASE_OUT_OF_SYNC) {
1095 log::info("Database out of sync for {}", device->addr);
1096 ClearDeviceInformationAndStartSearch(device);
1097 } else {
1098 log::error("Could not read characteristic at handle=0x{:04x}", handle);
1099 BTA_GATTC_Close(device->conn_id);
1100 }
1101 return;
1102 }
1103
1104 if (len != 1) {
1105 log::error("Invalid features value length={} at handle=0x{:x}", len,
1106 handle);
1107 BTA_GATTC_Close(device->conn_id);
1108 return;
1109 }
1110
1111 /* Store features value */
1112 uint8_t features;
1113 STREAM_TO_UINT8(features, value);
1114 device->UpdateFeatures(features);
1115
1116 if (device->isGattServiceValid()) {
1117 btif_storage_set_leaudio_has_features(device->addr, features);
1118 }
1119
1120 /* Journal update */
1121 device->has_journal_.Append(HasJournalRecord(features, true));
1122
1123 /* When service is not yet validated, report the available device with
1124 * features.
1125 */
1126 if (!device->isGattServiceValid())
1127 callbacks_->OnDeviceAvailable(device->addr, device->GetFeatures());
1128
1129 /* Notify features */
1130 callbacks_->OnFeaturesUpdate(device->addr, device->GetFeatures());
1131
1132 MarkDeviceValidIfInInitialDiscovery(*device);
1133 }
1134
1135 /* Translates GATT statuses to application specific error codes */
GattStatus2SvcErrorCode(tGATT_STATUS status)1136 static ErrorCode GattStatus2SvcErrorCode(tGATT_STATUS status) {
1137 switch (status) {
1138 case 0x80:
1139 /* Invalid Opcode */
1140 /* Unlikely to happen as we would not allow unsupported operations */
1141 return ErrorCode::OPERATION_NOT_SUPPORTED;
1142 case 0x81:
1143 /* Write Name Not Allowed */
1144 return ErrorCode::SET_NAME_NOT_ALLOWED;
1145 case 0x82:
1146 /* Synchronization Not Supported */
1147 return ErrorCode::OPERATION_NOT_SUPPORTED;
1148 case 0x83:
1149 /* Preset Operation Not Possible */
1150 return ErrorCode::OPERATION_NOT_POSSIBLE;
1151 case 0x84:
1152 /* Preset Name Too Long */
1153 return ErrorCode::INVALID_PRESET_NAME_LENGTH;
1154 case 0xFE:
1155 /* Procedure Already in Progress */
1156 return ErrorCode::PROCEDURE_ALREADY_IN_PROGRESS;
1157 default:
1158 return ErrorCode::OPERATION_NOT_POSSIBLE;
1159 }
1160 }
1161
OnHasPresetReadResponseNotification(HasDevice & device)1162 void OnHasPresetReadResponseNotification(HasDevice& device) {
1163 log::debug("");
1164
1165 while (device.ctp_notifications_.size() != 0) {
1166 auto ntf = device.ctp_notifications_.front();
1167 /* Process only read response events */
1168 if (ntf.opcode != PresetCtpOpcode::READ_PRESET_RESPONSE) break;
1169
1170 /* Update preset values */
1171 if (ntf.preset.has_value()) {
1172 device.has_presets.erase(ntf.preset->GetIndex());
1173 device.has_presets.insert(ntf.preset.value());
1174 }
1175
1176 /* We currently do READ_ALL_PRESETS only during the service validation.
1177 * If service is already valid, this must be the READ_PRESET_BY_INDEX.
1178 */
1179 if (device.isGattServiceValid()) {
1180 auto info = device.GetPresetInfo(ntf.preset.value().GetIndex());
1181 if (info.has_value())
1182 callbacks_->OnPresetInfo(
1183 device.addr, PresetInfoReason::PRESET_INFO_REQUEST_RESPONSE,
1184 {{info.value()}});
1185 }
1186
1187 /* Journal update */
1188 device.has_journal_.Append(HasJournalRecord(ntf));
1189 device.ctp_notifications_.pop_front();
1190 }
1191
1192 auto in_svc_validation = !device.isGattServiceValid();
1193 MarkDeviceValidIfInInitialDiscovery(device);
1194
1195 /* We currently do READ_ALL_PRESETS only during the service validation.
1196 * ALL_PRESET_INFO will be sent only during this initial phase.
1197 */
1198 if (in_svc_validation) {
1199 callbacks_->OnPresetInfo(device.addr, PresetInfoReason::ALL_PRESET_INFO,
1200 device.GetAllPresetInfo());
1201
1202 /* If this was the last validation step then send the currently active
1203 * preset as well.
1204 */
1205 if (device.isGattServiceValid())
1206 callbacks_->OnActivePresetSelected(device.addr,
1207 device.currently_active_preset);
1208 }
1209 }
1210
OnHasPresetGenericUpdate(HasDevice & device)1211 void OnHasPresetGenericUpdate(HasDevice& device) {
1212 log::verbose("");
1213
1214 std::vector<PresetInfo> updated_infos;
1215 std::vector<PresetInfo> deleted_infos;
1216
1217 /* Process the entire train of preset changes with generic updates */
1218 while (device.ctp_notifications_.size() != 0) {
1219 auto nt = device.ctp_notifications_.front();
1220
1221 /* Break if not a generic update anymore */
1222 if (nt.opcode != PresetCtpOpcode::PRESET_CHANGED) break;
1223 if (nt.change_id != PresetCtpChangeId::PRESET_GENERIC_UPDATE) break;
1224
1225 if (nt.preset.has_value()) {
1226 /* Erase in-between indices */
1227 auto it = device.has_presets.begin();
1228 while (it != device.has_presets.end()) {
1229 if ((it->GetIndex() > nt.prev_index) &&
1230 (it->GetIndex() < nt.preset->GetIndex())) {
1231 auto info = device.GetPresetInfo(it->GetIndex());
1232 if (info.has_value()) deleted_infos.push_back(info.value());
1233
1234 it = device.has_presets.erase(it);
1235
1236 } else {
1237 ++it;
1238 }
1239 }
1240 /* Update presets */
1241 auto info = device.GetPreset(nt.preset->GetIndex());
1242 if (info) {
1243 if (*info != *nt.preset) {
1244 device.has_presets.erase(nt.preset->GetIndex());
1245 device.has_presets.insert(*nt.preset);
1246 updated_infos.push_back(
1247 *device.GetPresetInfo(nt.preset->GetIndex()));
1248 }
1249 } else {
1250 device.has_presets.insert(*nt.preset);
1251 updated_infos.push_back(*device.GetPresetInfo(nt.preset->GetIndex()));
1252 }
1253 }
1254
1255 /* Journal update */
1256 device.has_journal_.Append(HasJournalRecord(nt));
1257 device.ctp_notifications_.pop_front();
1258 }
1259
1260 if (device.isGattServiceValid()) {
1261 /* Update preset values in the storage */
1262 std::vector<uint8_t> presets_bin;
1263 if (device.SerializePresets(presets_bin)) {
1264 btif_storage_set_leaudio_has_presets(device.addr, presets_bin);
1265 }
1266
1267 /* Check for the matching coordinated group op. to use group callbacks */
1268 for (auto it = pending_group_operation_timeouts_.rbegin();
1269 it != pending_group_operation_timeouts_.rend(); ++it) {
1270 auto& group_op_coordinator = it->second;
1271
1272 /* Here we interested only in valid preset name changes */
1273 if (!((group_op_coordinator.operation.opcode ==
1274 PresetCtpOpcode::WRITE_PRESET_NAME) &&
1275 group_op_coordinator.operation.name.has_value()))
1276 continue;
1277
1278 /* Match preset update results with the triggering operation */
1279 auto renamed_preset_info = std::find_if(
1280 updated_infos.begin(), updated_infos.end(),
1281 [&group_op_coordinator](const auto& info) {
1282 return (group_op_coordinator.operation.name.value() ==
1283 info.preset_name);
1284 });
1285 if (renamed_preset_info == updated_infos.end()) continue;
1286
1287 if (group_op_coordinator.SetCompleted(device.addr)) {
1288 group_op_coordinator.preset_info_verification_list.push_back(
1289 *renamed_preset_info);
1290
1291 /* Call the proper group operation completion callback */
1292 if (group_op_coordinator.IsFullyCompleted()) {
1293 callbacks_->OnPresetInfo(
1294 group_op_coordinator.operation.GetGroupId(),
1295 PresetInfoReason::PRESET_INFO_UPDATE, {*renamed_preset_info});
1296 pending_group_operation_timeouts_.erase(it->first);
1297 }
1298
1299 /* Erase it from the 'updated_infos' since later we'll be sending
1300 * this as a group callback when the other device completes the
1301 * coordinated group name change.
1302 *
1303 * WARNING: There might an issue with callbacks call reordering due to
1304 * some of them being kept for group callbacks called later, when all
1305 * the grouped devices complete the coordinated group rename
1306 * operation. In most cases this should not be a major problem.
1307 */
1308 updated_infos.erase(renamed_preset_info);
1309 break;
1310 }
1311 }
1312
1313 if (!updated_infos.empty()) {
1314 callbacks_->OnPresetInfo(
1315 device.addr, PresetInfoReason::PRESET_INFO_UPDATE, updated_infos);
1316 }
1317
1318 if (!deleted_infos.empty()) {
1319 callbacks_->OnPresetInfo(device.addr, PresetInfoReason::PRESET_DELETED,
1320 deleted_infos);
1321 }
1322 }
1323 }
1324
OnHasPresetAvailabilityChanged(HasDevice & device)1325 void OnHasPresetAvailabilityChanged(HasDevice& device) {
1326 log::debug("");
1327
1328 std::vector<PresetInfo> infos;
1329
1330 while (device.ctp_notifications_.size() != 0) {
1331 auto nt = device.ctp_notifications_.front();
1332
1333 /* Process only preset change notifications */
1334 if (nt.opcode != PresetCtpOpcode::PRESET_CHANGED) break;
1335
1336 auto preset = device.has_presets.extract(nt.index).value();
1337 auto new_props = preset.GetProperties();
1338
1339 /* Process only the preset availability changes and then notify */
1340 if ((nt.change_id != PresetCtpChangeId::PRESET_AVAILABLE) &&
1341 (nt.change_id != PresetCtpChangeId::PRESET_UNAVAILABLE))
1342 break;
1343
1344 /* Availability change */
1345 if (nt.change_id == PresetCtpChangeId::PRESET_AVAILABLE) {
1346 new_props |= HasPreset::kPropertyAvailable;
1347 } else {
1348 new_props &= !HasPreset::kPropertyAvailable;
1349 }
1350 device.has_presets.insert(
1351 HasPreset(preset.GetIndex(), new_props, preset.GetName()));
1352
1353 auto info = device.GetPresetInfo(nt.index);
1354 if (info.has_value()) infos.push_back(info.value());
1355
1356 /* Journal update */
1357 device.has_journal_.Append(HasJournalRecord(nt));
1358 device.ctp_notifications_.pop_front();
1359 }
1360
1361 /* Update preset storage */
1362 if (device.isGattServiceValid()) {
1363 std::vector<uint8_t> presets_bin;
1364 if (device.SerializePresets(presets_bin)) {
1365 btif_storage_set_leaudio_has_presets(device.addr, presets_bin);
1366 }
1367 }
1368
1369 callbacks_->OnPresetInfo(
1370 device.addr, PresetInfoReason::PRESET_AVAILABILITY_CHANGED, infos);
1371 }
1372
OnHasPresetDeleted(HasDevice & device)1373 void OnHasPresetDeleted(HasDevice& device) {
1374 log::debug("");
1375
1376 std::vector<PresetInfo> infos;
1377 bool is_deleted = false;
1378
1379 while (device.ctp_notifications_.size() != 0) {
1380 auto nt = device.ctp_notifications_.front();
1381
1382 /* Process only preset change notifications */
1383 if (nt.opcode != PresetCtpOpcode::PRESET_CHANGED) break;
1384
1385 /* Process only the deletions and then notify */
1386 if (nt.change_id != PresetCtpChangeId::PRESET_DELETED) break;
1387
1388 auto info = device.GetPresetInfo(nt.index);
1389 if (info.has_value()) infos.push_back(info.value());
1390
1391 if (device.has_presets.count(nt.index)) {
1392 is_deleted = true;
1393 device.has_presets.erase(nt.index);
1394 }
1395
1396 /* Journal update */
1397 device.has_journal_.Append(HasJournalRecord(nt));
1398 device.ctp_notifications_.pop_front();
1399 }
1400
1401 /* Update preset storage */
1402 if (device.isGattServiceValid()) {
1403 std::vector<uint8_t> presets_bin;
1404 if (device.SerializePresets(presets_bin)) {
1405 btif_storage_set_leaudio_has_presets(device.addr, presets_bin);
1406 }
1407 }
1408
1409 if (is_deleted)
1410 callbacks_->OnPresetInfo(device.addr, PresetInfoReason::PRESET_DELETED,
1411 infos);
1412 }
1413
ProcessCtpNotificationQueue(HasDevice & device)1414 void ProcessCtpNotificationQueue(HasDevice& device) {
1415 std::vector<PresetInfo> infos;
1416
1417 while (device.ctp_notifications_.size() != 0) {
1418 auto ntf = device.ctp_notifications_.front();
1419 log::debug("ntf: {}", ntf);
1420
1421 if (ntf.opcode == PresetCtpOpcode::PRESET_CHANGED) {
1422 switch (ntf.change_id) {
1423 case PresetCtpChangeId::PRESET_GENERIC_UPDATE:
1424 OnHasPresetGenericUpdate(device);
1425 break;
1426 case PresetCtpChangeId::PRESET_AVAILABLE:
1427 OnHasPresetAvailabilityChanged(device);
1428 break;
1429 case PresetCtpChangeId::PRESET_UNAVAILABLE:
1430 OnHasPresetAvailabilityChanged(device);
1431 break;
1432 case PresetCtpChangeId::PRESET_DELETED:
1433 OnHasPresetDeleted(device);
1434 break;
1435 default:
1436 log::error("Invalid notification: {}", ntf);
1437 break;
1438 }
1439
1440 } else if (ntf.opcode == PresetCtpOpcode::READ_PRESET_RESPONSE) {
1441 OnHasPresetReadResponseNotification(device);
1442
1443 } else {
1444 log::error("Unsupported preset notification: {}", ntf);
1445 }
1446 }
1447 }
1448
OnHasCtpValueNotification(HasDevice * device,uint16_t len,const uint8_t * value)1449 void OnHasCtpValueNotification(HasDevice* device, uint16_t len,
1450 const uint8_t* value) {
1451 auto ntf_opt = HasCtpNtf::FromCharacteristicValue(len, value);
1452 if (!ntf_opt.has_value()) {
1453 log::error("Unhandled notification for device: {}", *device);
1454 BTA_GATTC_Close(device->conn_id);
1455 return;
1456 }
1457
1458 auto ntf = ntf_opt.value();
1459 log::debug("{}", ntf);
1460
1461 device->ctp_notifications_.push_back(ntf);
1462 if (ntf.is_last) ProcessCtpNotificationQueue(*device);
1463 }
1464
OnHasActivePresetValue(std::variant<uint16_t,HasDevice * > conn_id_device_variant,tGATT_STATUS status,uint16_t handle,uint16_t len,const uint8_t * value,void * user_data=nullptr)1465 void OnHasActivePresetValue(
1466 std::variant<uint16_t, HasDevice*> conn_id_device_variant,
1467 tGATT_STATUS status, uint16_t handle, uint16_t len, const uint8_t* value,
1468 void* user_data = nullptr) {
1469 log::debug("");
1470
1471 auto device = GetDevice(conn_id_device_variant);
1472 if (!device) {
1473 log::error("Skipping unknown device!");
1474 return;
1475 }
1476
1477 if (status != GATT_SUCCESS) {
1478 if (status == GATT_DATABASE_OUT_OF_SYNC) {
1479 log::info("Database out of sync for {}", device->addr);
1480 ClearDeviceInformationAndStartSearch(device);
1481 } else {
1482 log::error("Could not read characteristic at handle=0x{:04x}", handle);
1483 BTA_GATTC_Close(device->conn_id);
1484 }
1485 }
1486
1487 if (len != 1) {
1488 log::error("Invalid preset value length={} at handle=0x{:x}", len,
1489 handle);
1490 BTA_GATTC_Close(device->conn_id);
1491 return;
1492 }
1493
1494 /* Get the active preset value */
1495 auto* pp = value;
1496 STREAM_TO_UINT8(device->currently_active_preset, pp);
1497
1498 if (device->isGattServiceValid()) {
1499 btif_storage_set_leaudio_has_active_preset(
1500 device->addr, device->currently_active_preset);
1501 }
1502
1503 /* Journal update */
1504 device->has_journal_.Append(
1505 HasJournalRecord(device->currently_active_preset, false));
1506
1507 /* If svc not marked valid, this might be the last validation step. */
1508 MarkDeviceValidIfInInitialDiscovery(*device);
1509
1510 if (device->isGattServiceValid()) {
1511 if (!pending_group_operation_timeouts_.empty()) {
1512 for (auto it = pending_group_operation_timeouts_.rbegin();
1513 it != pending_group_operation_timeouts_.rend(); ++it) {
1514 auto& group_op_coordinator = it->second;
1515
1516 bool matches = false;
1517 switch (group_op_coordinator.operation.opcode) {
1518 case PresetCtpOpcode::SET_ACTIVE_PRESET:
1519 [[fallthrough]];
1520 case PresetCtpOpcode::SET_NEXT_PRESET:
1521 [[fallthrough]];
1522 case PresetCtpOpcode::SET_PREV_PRESET:
1523 [[fallthrough]];
1524 case PresetCtpOpcode::SET_ACTIVE_PRESET_SYNC:
1525 [[fallthrough]];
1526 case PresetCtpOpcode::SET_NEXT_PRESET_SYNC:
1527 [[fallthrough]];
1528 case PresetCtpOpcode::SET_PREV_PRESET_SYNC: {
1529 if (group_op_coordinator.SetCompleted(device->addr)) {
1530 matches = true;
1531 break;
1532 }
1533 } break;
1534 default:
1535 /* Ignore */
1536 break;
1537 }
1538 if (group_op_coordinator.IsFullyCompleted()) {
1539 callbacks_->OnActivePresetSelected(
1540 group_op_coordinator.operation.GetGroupId(),
1541 device->currently_active_preset);
1542 pending_group_operation_timeouts_.erase(it->first);
1543 }
1544 if (matches) break;
1545 }
1546
1547 } else {
1548 callbacks_->OnActivePresetSelected(device->addr,
1549 device->currently_active_preset);
1550 }
1551 }
1552 }
1553
DeregisterNotifications(HasDevice & device)1554 void DeregisterNotifications(HasDevice& device) {
1555 /* Deregister from optional features notifications */
1556 if (device.features_ccc_handle != GAP_INVALID_HANDLE) {
1557 BTA_GATTC_DeregisterForNotifications(gatt_if_, device.addr,
1558 device.features_handle);
1559 }
1560
1561 /* Deregister from active presets notifications if presets exist */
1562 if (device.active_preset_ccc_handle != GAP_INVALID_HANDLE) {
1563 BTA_GATTC_DeregisterForNotifications(gatt_if_, device.addr,
1564 device.active_preset_handle);
1565 }
1566
1567 /* Deregister from control point notifications */
1568 if (device.cp_ccc_handle != GAP_INVALID_HANDLE) {
1569 BTA_GATTC_DeregisterForNotifications(gatt_if_, device.addr,
1570 device.cp_handle);
1571 }
1572 }
1573
1574 /* Cleans up after the device disconnection */
DoDisconnectCleanUp(HasDevice & device,bool invalidate_gatt_service=true)1575 void DoDisconnectCleanUp(HasDevice& device,
1576 bool invalidate_gatt_service = true) {
1577 log::debug(": device={}", device.addr);
1578
1579 DeregisterNotifications(device);
1580
1581 if (device.conn_id != GATT_INVALID_CONN_ID) {
1582 BtaGattQueue::Clean(device.conn_id);
1583 if (invalidate_gatt_service) device.gatt_svc_validation_steps = 0xFE;
1584 }
1585
1586 /* Clear pending operations */
1587 auto addr = device.addr;
1588 pending_operations_.erase(
1589 std::remove_if(
1590 pending_operations_.begin(), pending_operations_.end(),
1591 [&addr](auto& el) {
1592 if (std::holds_alternative<RawAddress>(el.addr_or_group)) {
1593 return std::get<RawAddress>(el.addr_or_group) == addr;
1594 }
1595 return false;
1596 }),
1597 pending_operations_.end());
1598
1599 device.ConnectionCleanUp();
1600 }
1601
1602 /* These below are all GATT service discovery, validation, cache & storage */
CacheAttributeHandles(const gatt::Service & service,HasDevice * device)1603 bool CacheAttributeHandles(const gatt::Service& service, HasDevice* device) {
1604 log::debug("device={}", device->addr);
1605
1606 for (const gatt::Characteristic& charac : service.characteristics) {
1607 if (charac.uuid == kUuidActivePresetIndex) {
1608 /* Find the mandatory CCC descriptor */
1609 uint16_t ccc_handle =
1610 FindCccHandle(device->conn_id, charac.value_handle);
1611 if (ccc_handle == GAP_INVALID_HANDLE) {
1612 log::error("no HAS Active Preset CCC descriptor found!");
1613 return false;
1614 }
1615 device->active_preset_ccc_handle = ccc_handle;
1616 device->active_preset_handle = charac.value_handle;
1617
1618 } else if (charac.uuid == kUuidHearingAidPresetControlPoint) {
1619 /* Find the mandatory CCC descriptor */
1620 uint16_t ccc_handle =
1621 FindCccHandle(device->conn_id, charac.value_handle);
1622 if (ccc_handle == GAP_INVALID_HANDLE) {
1623 log::error("no HAS Control Point CCC descriptor found!");
1624 return false;
1625 }
1626 uint8_t ccc_val = 0;
1627 if (charac.properties & GATT_CHAR_PROP_BIT_NOTIFY)
1628 ccc_val |= GATT_CHAR_CLIENT_CONFIG_NOTIFICATION;
1629
1630 if (charac.properties & GATT_CHAR_PROP_BIT_INDICATE)
1631 ccc_val |= GATT_CHAR_CLIENT_CONFIG_INDICTION;
1632
1633 if (ccc_val == 0) {
1634 log::error("Invalid properties for the control point 0x{:02x}",
1635 charac.properties);
1636 return false;
1637 }
1638
1639 device->cp_ccc_handle = ccc_handle;
1640 device->cp_handle = charac.value_handle;
1641 device->cp_ccc_val = ccc_val;
1642 } else if (charac.uuid == kUuidHearingAidFeatures) {
1643 /* Find the optional CCC descriptor */
1644 uint16_t ccc_handle =
1645 FindCccHandle(device->conn_id, charac.value_handle);
1646 device->features_ccc_handle = ccc_handle;
1647 device->features_handle = charac.value_handle;
1648 }
1649 }
1650 return true;
1651 }
1652
LoadHasDetailsFromStorage(HasDevice * device)1653 bool LoadHasDetailsFromStorage(HasDevice* device) {
1654 log::debug("device={}", device->addr);
1655
1656 std::vector<uint8_t> presets_bin;
1657 uint8_t active_preset;
1658
1659 if (!btif_storage_get_leaudio_has_presets(device->addr, presets_bin,
1660 active_preset))
1661 return false;
1662
1663 if (!HasDevice::DeserializePresets(presets_bin.data(), presets_bin.size(),
1664 *device))
1665 return false;
1666
1667 log::verbose("Loading HAS service details from storage.");
1668
1669 device->currently_active_preset = active_preset;
1670
1671 /* Update features and refresh opcode support map */
1672 uint8_t val;
1673 if (btif_storage_get_leaudio_has_features(device->addr, val))
1674 device->UpdateFeatures(val);
1675
1676 /* With all the details loaded we can already mark it as valid */
1677 device->gatt_svc_validation_steps = 0;
1678 device->is_connecting_actively = false;
1679
1680 NotifyHasDeviceValid(*device);
1681 callbacks_->OnPresetInfo(device->addr, PresetInfoReason::ALL_PRESET_INFO,
1682 device->GetAllPresetInfo());
1683 callbacks_->OnActivePresetSelected(device->addr,
1684 device->currently_active_preset);
1685 if (device->conn_id == GATT_INVALID_CONN_ID) return true;
1686
1687 /* Be mistrustful here: write CCC values even remote should have it */
1688 log::info("Subscribing for notification/indications");
1689 WriteAllNeededCcc(*device);
1690
1691 return true;
1692 }
1693
StartInitialHasDetailsReadAndValidation(const gatt::Service & service,HasDevice * device)1694 bool StartInitialHasDetailsReadAndValidation(const gatt::Service& service,
1695 HasDevice* device) {
1696 // Validate service structure
1697 if (device->features_handle == GAP_INVALID_HANDLE) {
1698 /* Missing key characteristic */
1699 log::error("Service has broken structure");
1700 return false;
1701 }
1702
1703 if (device->cp_handle != GAP_INVALID_HANDLE) {
1704 if (device->active_preset_handle == GAP_INVALID_HANDLE) return false;
1705 if (device->active_preset_ccc_handle == GAP_INVALID_HANDLE) return false;
1706 }
1707
1708 /* Number of reads or notifications required to validate the service */
1709 device->gatt_svc_validation_steps = 1 + (device->SupportsPresets() ? 2 : 0);
1710
1711 /* Read the initial features */
1712 BtaGattQueue::ReadCharacteristic(
1713 device->conn_id, device->features_handle,
1714 [](uint16_t conn_id, tGATT_STATUS status, uint16_t handle, uint16_t len,
1715 uint8_t* value, void* user_data) {
1716 if (instance)
1717 instance->OnHasFeaturesValue(conn_id, status, handle, len, value,
1718 user_data);
1719 },
1720 nullptr);
1721
1722 /* Register for features notifications */
1723 if (device->SupportsFeaturesNotification()) {
1724 SubscribeForNotifications(device->conn_id, device->addr,
1725 device->features_handle,
1726 device->features_ccc_handle);
1727 } else {
1728 log::warn("server does not support features notification");
1729 }
1730
1731 /* If Presets are supported we should read them all and subscribe for the
1732 * mandatory active preset index notifications.
1733 */
1734 if (device->SupportsPresets()) {
1735 /* Subscribe for active preset notifications */
1736 SubscribeForNotifications(device->conn_id, device->addr,
1737 device->active_preset_handle,
1738 device->active_preset_ccc_handle);
1739
1740 SubscribeForNotifications(device->conn_id, device->addr,
1741 device->cp_handle, device->cp_ccc_handle,
1742 device->cp_ccc_val);
1743
1744 /* Get all the presets */
1745 CpReadAllPresetsOperation(
1746 HasCtpOp(device->addr, PresetCtpOpcode::READ_PRESETS,
1747 bluetooth::le_audio::has::kStartPresetIndex,
1748 bluetooth::le_audio::has::kMaxNumOfPresets));
1749
1750 /* Read the current active preset index */
1751 BtaGattQueue::ReadCharacteristic(
1752 device->conn_id, device->active_preset_handle,
1753 [](uint16_t conn_id, tGATT_STATUS status, uint16_t handle,
1754 uint16_t len, uint8_t* value, void* user_data) {
1755 if (instance)
1756 instance->OnHasActivePresetValue(conn_id, status, handle, len,
1757 value, user_data);
1758 },
1759 nullptr);
1760 } else {
1761 log::warn(
1762 "server can only report HAS features, other functionality is "
1763 "disabled");
1764 }
1765
1766 return true;
1767 }
1768
OnHasServiceFound(const gatt::Service & service,void * context)1769 bool OnHasServiceFound(const gatt::Service& service, void* context) {
1770 log::debug("");
1771
1772 auto* device = static_cast<HasDevice*>(context);
1773
1774 /* Initially validate and store GATT service discovery data */
1775 if (!CacheAttributeHandles(service, device)) return false;
1776
1777 /* If deatails are loaded from storage we are done here */
1778 if (LoadHasDetailsFromStorage(device)) return true;
1779
1780 /* No storred details - read all the details and validate */
1781 return StartInitialHasDetailsReadAndValidation(service, device);
1782 }
1783
1784 /* These below are all generic event handlers calling in HAS specific code. */
GattcCallback(tBTA_GATTC_EVT event,tBTA_GATTC * p_data)1785 void GattcCallback(tBTA_GATTC_EVT event, tBTA_GATTC* p_data) {
1786 log::debug("event = {}", static_cast<int>(event));
1787
1788 switch (event) {
1789 case BTA_GATTC_DEREG_EVT:
1790 break;
1791
1792 case BTA_GATTC_OPEN_EVT:
1793 OnGattConnected(p_data->open);
1794 break;
1795
1796 case BTA_GATTC_CLOSE_EVT:
1797 OnGattDisconnected(p_data->close);
1798 break;
1799
1800 case BTA_GATTC_SEARCH_CMPL_EVT:
1801 OnGattServiceSearchComplete(p_data->search_cmpl);
1802 break;
1803
1804 case BTA_GATTC_NOTIF_EVT:
1805 OnGattNotification(p_data->notify);
1806 break;
1807
1808 case BTA_GATTC_ENC_CMPL_CB_EVT:
1809 OnLeEncryptionComplete(p_data->enc_cmpl.remote_bda,
1810 BTM_IsEncrypted(p_data->enc_cmpl.remote_bda, BT_TRANSPORT_LE));
1811 break;
1812
1813 case BTA_GATTC_SRVC_CHG_EVT:
1814 OnGattServiceChangeEvent(p_data->remote_bda);
1815 break;
1816
1817 case BTA_GATTC_SRVC_DISC_DONE_EVT:
1818 OnGattServiceDiscoveryDoneEvent(p_data->remote_bda);
1819 break;
1820
1821 default:
1822 break;
1823 }
1824 }
1825
OnGattConnected(const tBTA_GATTC_OPEN & evt)1826 void OnGattConnected(const tBTA_GATTC_OPEN& evt) {
1827 log::info("{}, conn_id=0x{:04x}, transport={}, status={}(0x{:02x})",
1828 evt.remote_bda, evt.conn_id, bt_transport_text(evt.transport),
1829 gatt_status_text(evt.status), evt.status);
1830
1831 if (evt.transport != BT_TRANSPORT_LE) {
1832 log::warn("Only LE connection is allowed (transport {})",
1833 bt_transport_text(evt.transport));
1834 BTA_GATTC_Close(evt.conn_id);
1835 return;
1836 }
1837
1838 auto device = std::find_if(devices_.begin(), devices_.end(),
1839 HasDevice::MatchAddress(evt.remote_bda));
1840 if (device == devices_.end()) {
1841 log::warn("Skipping unknown device, address={}", evt.remote_bda);
1842 BTA_GATTC_Close(evt.conn_id);
1843 return;
1844 }
1845
1846 if (evt.status != GATT_SUCCESS) {
1847 if (!device->is_connecting_actively) {
1848 // acceptlist connection failed, that's ok.
1849 return;
1850 }
1851
1852 log::warn("Failed to connect to server device");
1853 devices_.erase(device);
1854 callbacks_->OnConnectionState(ConnectionState::DISCONNECTED,
1855 evt.remote_bda);
1856 return;
1857 }
1858
1859 device->conn_id = evt.conn_id;
1860
1861 if (BTM_SecIsSecurityPending(device->addr)) {
1862 /* if security collision happened, wait for encryption done
1863 * (BTA_GATTC_ENC_CMPL_CB_EVT)
1864 */
1865 return;
1866 }
1867
1868 /* verify bond */
1869 if (BTM_IsEncrypted(device->addr, BT_TRANSPORT_LE)) {
1870 /* if link has been encrypted */
1871 OnEncrypted(*device);
1872 return;
1873 }
1874
1875 int result = BTM_SetEncryption(device->addr, BT_TRANSPORT_LE, nullptr,
1876 nullptr, BTM_BLE_SEC_ENCRYPT);
1877
1878 log::info("Encryption required for {}. Request result: 0x{:02x}",
1879 device->addr, result);
1880
1881 if (result == BTM_ERR_KEY_MISSING) {
1882 log::error("Link key unknown for {}, disconnect profile", device->addr);
1883 BTA_GATTC_Close(device->conn_id);
1884 }
1885 }
1886
OnGattDisconnected(const tBTA_GATTC_CLOSE & evt)1887 void OnGattDisconnected(const tBTA_GATTC_CLOSE& evt) {
1888 auto device = std::find_if(devices_.begin(), devices_.end(),
1889 HasDevice::MatchAddress(evt.remote_bda));
1890 if (device == devices_.end()) {
1891 log::warn("Skipping unknown device disconnect, conn_id=0x{:x}",
1892 evt.conn_id);
1893 return;
1894 }
1895 log::debug("device={}: reason=0x{:x}", device->addr,
1896 static_cast<int>(evt.reason));
1897
1898 /* Don't notify disconnect state for background connection that failed */
1899 if (device->is_connecting_actively || device->isGattServiceValid())
1900 callbacks_->OnConnectionState(ConnectionState::DISCONNECTED,
1901 evt.remote_bda);
1902
1903 auto peer_disconnected = (evt.reason == GATT_CONN_TIMEOUT) ||
1904 (evt.reason == GATT_CONN_TERMINATE_PEER_USER);
1905 DoDisconnectCleanUp(*device, peer_disconnected ? false : true);
1906
1907 /* Connect in background - is this ok? */
1908 if (peer_disconnected)
1909 BTA_GATTC_Open(gatt_if_, device->addr, BTM_BLE_BKG_CONNECT_ALLOW_LIST,
1910 false);
1911 }
1912
OnGattServiceSearchComplete(const tBTA_GATTC_SEARCH_CMPL & evt)1913 void OnGattServiceSearchComplete(const tBTA_GATTC_SEARCH_CMPL& evt) {
1914 auto device = GetDevice(evt.conn_id);
1915 if (!device) {
1916 log::warn("Skipping unknown device, conn_id=0x{:x}", evt.conn_id);
1917 return;
1918 }
1919
1920 log::debug("");
1921
1922 /* verify link is encrypted */
1923 if (!BTM_IsEncrypted(device->addr, BT_TRANSPORT_LE)) {
1924 log::warn("Device not yet bonded - waiting for encryption");
1925 return;
1926 }
1927
1928 /* Ignore if our service data is valid (service discovery initiated by
1929 * someone else?)
1930 */
1931 if (!device->isGattServiceValid()) {
1932 if (evt.status != GATT_SUCCESS) {
1933 log::error("Service discovery failed");
1934 BTA_GATTC_Close(device->conn_id);
1935 return;
1936 }
1937
1938 const std::list<gatt::Service>* all_services =
1939 BTA_GATTC_GetServices(device->conn_id);
1940
1941 auto service =
1942 std::find_if(all_services->begin(), all_services->end(),
1943 [](const gatt::Service& svc) {
1944 return svc.uuid == kUuidHearingAccessService;
1945 });
1946 if (service == all_services->end()) {
1947 log::error("No service found");
1948 BTA_GATTC_Close(device->conn_id);
1949 return;
1950 }
1951
1952 /* Call the service specific verifier callback */
1953 if (!instance->OnHasServiceFound(*service, &(*device))) {
1954 log::error("Not a valid service!");
1955 BTA_GATTC_Close(device->conn_id);
1956 return;
1957 }
1958 }
1959 }
1960
OnGattNotification(const tBTA_GATTC_NOTIFY & evt)1961 void OnGattNotification(const tBTA_GATTC_NOTIFY& evt) {
1962 /* Reject invalid lengths */
1963 if (evt.len > GATT_MAX_ATTR_LEN) {
1964 log::error("rejected BTA_GATTC_NOTIF_EVT. is_notify = {}, len={}",
1965 evt.is_notify, static_cast<int>(evt.len));
1966 }
1967 if (!evt.is_notify) BTA_GATTC_SendIndConfirm(evt.conn_id, evt.cid);
1968
1969 OnHasNotification(evt.conn_id, evt.handle, evt.len, evt.value);
1970 }
1971
OnLeEncryptionComplete(const RawAddress & address,bool success)1972 void OnLeEncryptionComplete(const RawAddress& address, bool success) {
1973 log::debug("{}", address);
1974
1975 auto device = std::find_if(devices_.begin(), devices_.end(),
1976 HasDevice::MatchAddress(address));
1977 if (device == devices_.end()) {
1978 log::warn("Skipping unknown device{}", address);
1979 return;
1980 }
1981
1982 if (!success) {
1983 log::error("Encryption failed for device {}", address);
1984
1985 BTA_GATTC_Close(device->conn_id);
1986 return;
1987 }
1988
1989 if (device->isGattServiceValid()) {
1990 instance->OnEncrypted(*device);
1991 } else {
1992 BTA_GATTC_ServiceSearchRequest(device->conn_id,
1993 kUuidHearingAccessService);
1994 }
1995 }
1996
ClearDeviceInformationAndStartSearch(HasDevice * device)1997 void ClearDeviceInformationAndStartSearch(HasDevice* device) {
1998 if (!device) {
1999 log::error("Device is null");
2000 return;
2001 }
2002
2003 log::info("{}", device->addr);
2004
2005 if (!device->isGattServiceValid()) {
2006 log::info("Service already invalidated");
2007 return;
2008 }
2009
2010 /* Invalidate service discovery results */
2011 DeregisterNotifications(*device);
2012 BtaGattQueue::Clean(device->conn_id);
2013 device->ClearSvcData();
2014 btif_storage_remove_leaudio_has(device->addr);
2015 BTA_GATTC_ServiceSearchRequest(device->conn_id, kUuidHearingAccessService);
2016 }
2017
OnGattServiceChangeEvent(const RawAddress & address)2018 void OnGattServiceChangeEvent(const RawAddress& address) {
2019 auto device = std::find_if(devices_.begin(), devices_.end(),
2020 HasDevice::MatchAddress(address));
2021 if (device == devices_.end()) {
2022 log::warn("Skipping unknown device: {}", address);
2023 return;
2024 }
2025 log::info("{}", address);
2026 ClearDeviceInformationAndStartSearch(&(*device));
2027 }
2028
OnGattServiceDiscoveryDoneEvent(const RawAddress & address)2029 void OnGattServiceDiscoveryDoneEvent(const RawAddress& address) {
2030 auto device = std::find_if(devices_.begin(), devices_.end(),
2031 HasDevice::MatchAddress(address));
2032 if (device == devices_.end()) {
2033 log::warn("Skipping unknown device: {}", address);
2034 return;
2035 }
2036
2037 log::debug("address={}", address);
2038
2039 if (!device->isGattServiceValid())
2040 BTA_GATTC_ServiceSearchRequest(device->conn_id,
2041 kUuidHearingAccessService);
2042 }
2043
FindCccHandle(uint16_t conn_id,uint16_t char_handle)2044 static uint16_t FindCccHandle(uint16_t conn_id, uint16_t char_handle) {
2045 const gatt::Characteristic* p_char =
2046 BTA_GATTC_GetCharacteristic(conn_id, char_handle);
2047 if (!p_char) {
2048 log::warn("No such characteristic: {}", char_handle);
2049 return GAP_INVALID_HANDLE;
2050 }
2051
2052 for (const gatt::Descriptor& desc : p_char->descriptors) {
2053 if (desc.uuid == Uuid::From16Bit(GATT_UUID_CHAR_CLIENT_CONFIG))
2054 return desc.handle;
2055 }
2056
2057 return GAP_INVALID_HANDLE;
2058 }
2059
SubscribeForNotifications(uint16_t conn_id,const RawAddress & address,uint16_t value_handle,uint16_t ccc_handle,uint16_t ccc_val=GATT_CHAR_CLIENT_CONFIG_NOTIFICATION)2060 void SubscribeForNotifications(
2061 uint16_t conn_id, const RawAddress& address, uint16_t value_handle,
2062 uint16_t ccc_handle,
2063 uint16_t ccc_val = GATT_CHAR_CLIENT_CONFIG_NOTIFICATION) {
2064 if (value_handle != GAP_INVALID_HANDLE) {
2065 tGATT_STATUS register_status =
2066 BTA_GATTC_RegisterForNotifications(gatt_if_, address, value_handle);
2067 log::debug(
2068 "BTA_GATTC_RegisterForNotifications, status=0x{:x} value=0x{:x} "
2069 "ccc=0x{:x}",
2070 register_status, value_handle, ccc_handle);
2071
2072 if (register_status != GATT_SUCCESS) return;
2073 }
2074
2075 std::vector<uint8_t> value(2);
2076 uint8_t* value_ptr = value.data();
2077 UINT16_TO_STREAM(value_ptr, ccc_val);
2078 BtaGattQueue::WriteDescriptor(
2079 conn_id, ccc_handle, std::move(value), GATT_WRITE,
2080 [](uint16_t conn_id, tGATT_STATUS status, uint16_t value_handle,
2081 uint16_t len, const uint8_t* value, void* data) {
2082 if (instance)
2083 instance->OnGattWriteCcc(conn_id, status, value_handle, data);
2084 },
2085 HasGattOpContext(HasGattOpContext::kContextFlagsEnableNotification));
2086 }
2087
2088 uint8_t gatt_if_;
2089 bluetooth::has::HasClientCallbacks* callbacks_;
2090 std::list<HasDevice> devices_;
2091 std::list<HasCtpOp> pending_operations_;
2092
2093 typedef std::map<decltype(HasCtpOp::op_id), HasCtpGroupOpCoordinator>
2094 has_operation_timeouts_t;
2095 has_operation_timeouts_t pending_group_operation_timeouts_;
2096 };
2097
2098 } // namespace
2099
2100 alarm_t* HasCtpGroupOpCoordinator::operation_timeout_timer = nullptr;
2101 size_t HasCtpGroupOpCoordinator::ref_cnt = 0u;
__anon4af03b2d1202(void*) 2102 alarm_callback_t HasCtpGroupOpCoordinator::cb = [](void*) {};
2103
Initialize(bluetooth::has::HasClientCallbacks * callbacks,base::Closure initCb)2104 void HasClient::Initialize(bluetooth::has::HasClientCallbacks* callbacks,
2105 base::Closure initCb) {
2106 std::scoped_lock<std::mutex> lock(instance_mutex);
2107 if (instance) {
2108 log::error("Already initialized!");
2109 return;
2110 }
2111
2112 HasCtpGroupOpCoordinator::Initialize([](void* p) {
2113 if (instance) instance->OnGroupOpCoordinatorTimeout(p);
2114 });
2115 instance = new HasClientImpl(callbacks, initCb);
2116 }
2117
IsHasClientRunning()2118 bool HasClient::IsHasClientRunning() { return instance; }
2119
Get(void)2120 HasClient* HasClient::Get(void) {
2121 log::assert_that(instance != nullptr, "assert failed: instance != nullptr");
2122 return instance;
2123 };
2124
AddFromStorage(const RawAddress & addr,uint8_t features,uint16_t is_acceptlisted)2125 void HasClient::AddFromStorage(const RawAddress& addr, uint8_t features,
2126 uint16_t is_acceptlisted) {
2127 if (!instance) {
2128 log::error("Not initialized yet");
2129 }
2130
2131 instance->AddFromStorage(addr, features, is_acceptlisted);
2132 };
2133
CleanUp()2134 void HasClient::CleanUp() {
2135 std::scoped_lock<std::mutex> lock(instance_mutex);
2136 HasClientImpl* ptr = instance;
2137 instance = nullptr;
2138
2139 if (ptr) {
2140 ptr->CleanUp();
2141 delete ptr;
2142 }
2143
2144 HasCtpGroupOpCoordinator::Cleanup();
2145 };
2146
DebugDump(int fd)2147 void HasClient::DebugDump(int fd) {
2148 std::scoped_lock<std::mutex> lock(instance_mutex);
2149 dprintf(fd, "Hearing Access Service Client:\n");
2150 if (instance)
2151 instance->Dump(fd);
2152 else
2153 dprintf(fd, " no instance\n\n");
2154 }
2155