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