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